<!DOCTYPE html><html lang="zh-CN" data-theme="light"><head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no"><title>SpringMVC框架 | zylai</title><meta name="keywords" content="框架,Spring Framework,web应用"><meta name="author" content="zylai"><meta name="copyright" content="zylai"><meta name="format-detection" content="telephone=no"><meta name="theme-color" content="#ffffff"><meta name="description" content="SpringMVC 1 SpringMVC简介 1.1 MVC 是一种架构思想，不是框架或者设计模式 1.2 SpringMVC 是Spring为表述层开发提供的一整套完备的解决方案，封装的就是servlet。  三层架构，是指的表述层、业务逻辑层、数据访问层，表述层表示前台页面和后台servlet  1.3 SpringMVC的特点  Spring 家族原生产品，与 IOC 容器等基础设施无缝对">
<meta property="og:type" content="article">
<meta property="og:title" content="SpringMVC框架">
<meta property="og:url" content="https://zhaoyunlai.gitee.io/posts/97f98a11ca37/index.html">
<meta property="og:site_name" content="zylai">
<meta property="og:description" content="SpringMVC 1 SpringMVC简介 1.1 MVC 是一种架构思想，不是框架或者设计模式 1.2 SpringMVC 是Spring为表述层开发提供的一整套完备的解决方案，封装的就是servlet。  三层架构，是指的表述层、业务逻辑层、数据访问层，表述层表示前台页面和后台servlet  1.3 SpringMVC的特点  Spring 家族原生产品，与 IOC 容器等基础设施无缝对">
<meta property="og:locale" content="zh_CN">
<meta property="og:image" content="https://zylai-cloud-pic-1306915061.cos.ap-nanjing.myqcloud.com/images01/SpringMVC.assets/SpringMVC-logo.png">
<meta property="article:published_time" content="2022-08-02T11:57:26.000Z">
<meta property="article:modified_time" content="2022-08-04T13:17:57.215Z">
<meta property="article:author" content="zylai">
<meta property="article:tag" content="框架">
<meta property="article:tag" content="Spring Framework">
<meta property="article:tag" content="web应用">
<meta name="twitter:card" content="summary">
<meta name="twitter:image" content="https://zylai-cloud-pic-1306915061.cos.ap-nanjing.myqcloud.com/images01/SpringMVC.assets/SpringMVC-logo.png"><link rel="shortcut icon" href="/img/favicon.png"><link rel="canonical" href="https://zhaoyunlai.gitee.io/posts/97f98a11ca37/"><link rel="preconnect" href="//cdn.jsdelivr.net"/><link rel="preconnect" href="//hm.baidu.com"/><link rel="preconnect" href="//busuanzi.ibruce.info"/><link rel="stylesheet" href="/css/index.css"><link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fortawesome/fontawesome-free/css/all.min.css" media="print" onload="this.media='all'"><link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fancyapps/ui/dist/fancybox.min.css" media="print" onload="this.media='all'"><script>var _hmt = _hmt || [];
(function() {
  var hm = document.createElement("script");
  hm.src = "https://hm.baidu.com/hm.js?ec7714e43e379e663d7258bb72abd0cc";
  var s = document.getElementsByTagName("script")[0]; 
  s.parentNode.insertBefore(hm, s);
})();
</script><script>const GLOBAL_CONFIG = { 
  root: '/',
  algolia: undefined,
  localSearch: {"path":"/search.xml","preload":false,"languages":{"hits_empty":"找不到您查询的内容：${query}"}},
  translate: undefined,
  noticeOutdate: undefined,
  highlight: {"plugin":"highlighjs","highlightCopy":true,"highlightLang":true,"highlightHeightLimit":false},
  copy: {
    success: '复制成功',
    error: '复制错误',
    noSupport: '浏览器不支持'
  },
  relativeDate: {
    homepage: false,
    post: false
  },
  runtime: '',
  date_suffix: {
    just: '刚刚',
    min: '分钟前',
    hour: '小时前',
    day: '天前',
    month: '个月前'
  },
  copyright: undefined,
  lightbox: 'fancybox',
  Snackbar: undefined,
  source: {
    justifiedGallery: {
      js: 'https://cdn.jsdelivr.net/npm/flickr-justified-gallery/dist/fjGallery.min.js',
      css: 'https://cdn.jsdelivr.net/npm/flickr-justified-gallery/dist/fjGallery.min.css'
    }
  },
  isPhotoFigcaption: false,
  islazyload: false,
  isAnchor: false
}</script><script id="config-diff">var GLOBAL_CONFIG_SITE = {
  title: 'SpringMVC框架',
  isPost: true,
  isHome: false,
  isHighlightShrink: false,
  isToc: true,
  postUpdate: '2022-08-04 21:17:57'
}</script><noscript><style type="text/css">
  #nav {
    opacity: 1
  }
  .justified-gallery img {
    opacity: 1
  }

  #recent-posts time,
  #post-meta time {
    display: inline !important
  }
</style></noscript><script>(win=>{
    win.saveToLocal = {
      set: function setWithExpiry(key, value, ttl) {
        if (ttl === 0) return
        const now = new Date()
        const expiryDay = ttl * 86400000
        const item = {
          value: value,
          expiry: now.getTime() + expiryDay,
        }
        localStorage.setItem(key, JSON.stringify(item))
      },

      get: function getWithExpiry(key) {
        const itemStr = localStorage.getItem(key)

        if (!itemStr) {
          return undefined
        }
        const item = JSON.parse(itemStr)
        const now = new Date()

        if (now.getTime() > item.expiry) {
          localStorage.removeItem(key)
          return undefined
        }
        return item.value
      }
    }
  
    win.getScript = url => new Promise((resolve, reject) => {
      const script = document.createElement('script')
      script.src = url
      script.async = true
      script.onerror = reject
      script.onload = script.onreadystatechange = function() {
        const loadState = this.readyState
        if (loadState && loadState !== 'loaded' && loadState !== 'complete') return
        script.onload = script.onreadystatechange = null
        resolve()
      }
      document.head.appendChild(script)
    })
  
      win.activateDarkMode = function () {
        document.documentElement.setAttribute('data-theme', 'dark')
        if (document.querySelector('meta[name="theme-color"]') !== null) {
          document.querySelector('meta[name="theme-color"]').setAttribute('content', '#0d0d0d')
        }
      }
      win.activateLightMode = function () {
        document.documentElement.setAttribute('data-theme', 'light')
        if (document.querySelector('meta[name="theme-color"]') !== null) {
          document.querySelector('meta[name="theme-color"]').setAttribute('content', '#ffffff')
        }
      }
      const t = saveToLocal.get('theme')
    
          if (t === 'dark') activateDarkMode()
          else if (t === 'light') activateLightMode()
        
      const asideStatus = saveToLocal.get('aside-status')
      if (asideStatus !== undefined) {
        if (asideStatus === 'hide') {
          document.documentElement.classList.add('hide-aside')
        } else {
          document.documentElement.classList.remove('hide-aside')
        }
      }
    
    const detectApple = () => {
      if(/iPad|iPhone|iPod|Macintosh/.test(navigator.userAgent)){
        document.documentElement.classList.add('apple')
      }
    }
    detectApple()
    })(window)</script><!-- hexo injector head_end start --><link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/Zfour/hexo-electric-clock@1.0.6/clock.css"><!-- hexo injector head_end end --><meta name="generator" content="Hexo 5.4.2"></head><body><div id="web_bg"></div><div id="sidebar"><div id="menu-mask"></div><div id="sidebar-menus"><div class="avatar-img is-center"><img src="/img/avatar.jpg" onerror="onerror=null;src='/img/friend_404.gif'" alt="avatar"/></div><div class="sidebar-site-data site-data is-center"><a href="/archives/"><div class="headline">文章</div><div class="length-num">18</div></a><a href="/tags/"><div class="headline">标签</div><div class="length-num">14</div></a><a href="/categories/"><div class="headline">分类</div><div class="length-num">11</div></a></div><hr/><div class="menus_items"><div class="menus_item"><a class="site-page" href="/"><i class="fa-fw fas fa-home"></i><span> 首页</span></a></div><div class="menus_item"><a class="site-page" href="/archives/"><i class="fa-fw fas fa-archive"></i><span> 时间轴</span></a></div><div class="menus_item"><a class="site-page" href="/tags/"><i class="fa-fw fas fa-tags"></i><span> 标签</span></a></div><div class="menus_item"><a class="site-page" href="/categories/"><i class="fa-fw fas fa-folder-open"></i><span> 分类</span></a></div><div class="menus_item"><a class="site-page" href="/link/"><i class="fa-fw fas fa-link"></i><span> 友链</span></a></div><div class="menus_item"><a class="site-page" href="/about/"><i class="fa-fw fas fa-heart"></i><span> 关于</span></a></div></div></div></div><div class="post" id="body-wrap"><header class="post-bg" id="page-header" style="background-image: url('https://zylai-cloud-pic-1306915061.cos.ap-nanjing.myqcloud.com/images01/SpringMVC.assets/SpringMVC-logo.png')"><nav id="nav"><span id="blog_name"><a id="site-name" href="/">zylai</a></span><div id="menus"><div id="search-button"><a class="site-page social-icon search"><i class="fas fa-search fa-fw"></i><span> 搜索</span></a></div><div class="menus_items"><div class="menus_item"><a class="site-page" href="/"><i class="fa-fw fas fa-home"></i><span> 首页</span></a></div><div class="menus_item"><a class="site-page" href="/archives/"><i class="fa-fw fas fa-archive"></i><span> 时间轴</span></a></div><div class="menus_item"><a class="site-page" href="/tags/"><i class="fa-fw fas fa-tags"></i><span> 标签</span></a></div><div class="menus_item"><a class="site-page" href="/categories/"><i class="fa-fw fas fa-folder-open"></i><span> 分类</span></a></div><div class="menus_item"><a class="site-page" href="/link/"><i class="fa-fw fas fa-link"></i><span> 友链</span></a></div><div class="menus_item"><a class="site-page" href="/about/"><i class="fa-fw fas fa-heart"></i><span> 关于</span></a></div></div><div id="toggle-menu"><a class="site-page"><i class="fas fa-bars fa-fw"></i></a></div></div></nav><div id="post-info"><h1 class="post-title">SpringMVC框架</h1><div id="post-meta"><div class="meta-firstline"><span class="post-meta-date"><i class="far fa-calendar-alt fa-fw post-meta-icon"></i><span class="post-meta-label">发表于</span><time class="post-meta-date-created" datetime="2022-08-02T11:57:26.000Z" title="发表于 2022-08-02 19:57:26">2022-08-02</time><span class="post-meta-separator">|</span><i class="fas fa-history fa-fw post-meta-icon"></i><span class="post-meta-label">更新于</span><time class="post-meta-date-updated" datetime="2022-08-04T13:17:57.215Z" title="更新于 2022-08-04 21:17:57">2022-08-04</time></span><span class="post-meta-categories"><span class="post-meta-separator">|</span><i class="fas fa-inbox fa-fw post-meta-icon"></i><a class="post-meta-categories" href="/categories/SpringMVC/">SpringMVC</a></span></div><div class="meta-secondline"><span class="post-meta-separator">|</span><span class="post-meta-pv-cv" id="" data-flag-title="SpringMVC框架"><i class="far fa-eye fa-fw post-meta-icon"></i><span class="post-meta-label">阅读量:</span><span id="busuanzi_value_page_pv"><i class="fa-solid fa-spinner fa-spin"></i></span></span></div></div></div></header><main class="layout" id="content-inner"><div id="post"><article class="post-content" id="article-container"><h1>SpringMVC</h1>
<h2 id="1-SpringMVC简介">1 SpringMVC简介</h2>
<h3 id="1-1-MVC">1.1 MVC</h3>
<p>是一种架构思想，不是框架或者设计模式</p>
<h3 id="1-2-SpringMVC">1.2 SpringMVC</h3>
<p>是Spring为<strong>表述层</strong>开发提供的一整套完备的解决方案，封装的就是servlet。</p>
<blockquote>
<p>三层架构，是指的表述层、业务逻辑层、数据访问层，表述层表示前台页面和后台servlet</p>
</blockquote>
<h3 id="1-3-SpringMVC的特点">1.3 SpringMVC的特点</h3>
<ul>
<li>Spring 家族原生产品，与 IOC 容器等基础设施无缝对接</li>
<li>基于原生的Servlet，通过了功能强大的前端控制器DispatcherServlet，对请求和响应进行统一处理</li>
<li>表述层各细分领域需要解决的问题全方位覆盖，提供全面解决方案</li>
<li>代码清新简洁，大幅度提升开发效率</li>
<li>内部组件化程度高，可插拔式组件即插即用，想要什么功能配置相应组件即可</li>
<li>性能卓著，尤其适合现代大型、超大型互联网项目要求</li>
</ul>
<h2 id="2-入门案例💃">2 入门案例💃</h2>
<h3 id="2-1-创建Maven工程">2.1 创建Maven工程</h3>
<ol>
<li>添加web模块</li>
</ol>
<blockquote>
<p>这里是以另外一个模块为例</p>
</blockquote>
<p><img src="https://zylai-cloud-pic-1306915061.cos.ap-nanjing.myqcloud.com/images01/SpringMVC.assets/image-20220728191705230.png" alt="image-20220728191705230"></p>
<ol start="2">
<li>打包方式设置为war</li>
<li>引入依赖</li>
</ol>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">dependencies</span>&gt;</span></span><br><span class="line">       <span class="comment">&lt;!-- SpringMVC --&gt;</span></span><br><span class="line">       <span class="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line">           <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>org.springframework<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">           <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>spring-webmvc<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line">           <span class="tag">&lt;<span class="name">version</span>&gt;</span>5.3.1<span class="tag">&lt;/<span class="name">version</span>&gt;</span></span><br><span class="line">       <span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br><span class="line"></span><br><span class="line">       <span class="comment">&lt;!--thymeleaf需要slf4j日志接口，这里引入他的一个实现logback--&gt;</span></span><br><span class="line">       <span class="comment">&lt;!-- 日志 --&gt;</span></span><br><span class="line">       <span class="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line">           <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>ch.qos.logback<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">           <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>logback-classic<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line">           <span class="tag">&lt;<span class="name">version</span>&gt;</span>1.2.3<span class="tag">&lt;/<span class="name">version</span>&gt;</span></span><br><span class="line">       <span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br><span class="line">       <span class="comment">&lt;!-- ServletAPI --&gt;</span></span><br><span class="line">       <span class="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line">           <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>javax.servlet<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">           <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>javax.servlet-api<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line">           <span class="tag">&lt;<span class="name">version</span>&gt;</span>3.1.0<span class="tag">&lt;/<span class="name">version</span>&gt;</span></span><br><span class="line">           <span class="tag">&lt;<span class="name">scope</span>&gt;</span>provided<span class="tag">&lt;/<span class="name">scope</span>&gt;</span></span><br><span class="line">       <span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br><span class="line">       <span class="comment">&lt;!-- Spring5和Thymeleaf整合包 --&gt;</span></span><br><span class="line">       <span class="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line">           <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>org.thymeleaf<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">           <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>thymeleaf-spring5<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line">           <span class="tag">&lt;<span class="name">version</span>&gt;</span>3.0.12.RELEASE<span class="tag">&lt;/<span class="name">version</span>&gt;</span></span><br><span class="line">       <span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br><span class="line">   <span class="tag">&lt;/<span class="name">dependencies</span>&gt;</span></span><br></pre></td></tr></table></figure>
<p>注：由于 Maven 的传递性，我们不必将所有需要的包全部配置依赖，而是配置最顶端的依赖，其他靠传递性导入。</p>
<p><img src="https://zylai-cloud-pic-1306915061.cos.ap-nanjing.myqcloud.com/images01/SpringMVC.assets/image-20220728185146508.png" alt="image-20220728185146508"></p>
<h3 id="2-2-在web-xml中配置DispatcherServlet">2.2 在web.xml中配置DispatcherServlet</h3>
<h4 id="2-2-1-配置匹配请求路径">2.2.1 配置匹配请求路径</h4>
<p>匹配请求时：写<code>/</code>，匹配浏览器向服务器发送的所有请求，但是不包括以.jsp结尾的请求</p>
<p>而<code>/*</code>，可以匹配.jsp的请求，但是DispatcherServlet不能处理这种请求，需要Tomcat中专门的的处理.jsp请求的servlet</p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">servlet-mapping</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">servlet-name</span>&gt;</span>SpringMVC<span class="tag">&lt;/<span class="name">servlet-name</span>&gt;</span></span><br><span class="line">    <span class="comment">&lt;!--这里写/，匹配浏览器向服务器发送的所有请求，但是不包括以.jsp结尾的请求</span></span><br><span class="line"><span class="comment">        而/*,可以匹配.jsp的请求</span></span><br><span class="line"><span class="comment">        而DispatcherServlet不能处理这种请求，Tomcat中有专门的的处理.jsp的请求--&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">url-pattern</span>&gt;</span>/<span class="tag">&lt;/<span class="name">url-pattern</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">servlet-mapping</span>&gt;</span></span><br></pre></td></tr></table></figure>
<h4 id="2-2-2-配置初始化时机">2.2.2 配置初始化时机</h4>
<p>由于DispatcherServlet初始化时间很久，所以非常有必要提前初始化</p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">load-on-startup</span>&gt;</span>1<span class="tag">&lt;/<span class="name">load-on-startup</span>&gt;</span></span><br></pre></td></tr></table></figure>
<h4 id="2-2-3-配置文件的路径">2.2.3 配置文件的路径</h4>
<p>这里使用类路径</p>
<blockquote>
<p>类路径：是指java和resources下的路径</p>
</blockquote>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">init-param</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">param-name</span>&gt;</span>contextConfigLocation<span class="tag">&lt;/<span class="name">param-name</span>&gt;</span></span><br><span class="line">    <span class="comment">&lt;!--类路径：是指java和resources下的路径--&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">param-value</span>&gt;</span>classpath:springmvc.xml<span class="tag">&lt;/<span class="name">param-value</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">init-param</span>&gt;</span></span><br></pre></td></tr></table></figure>
<p>总文件：</p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">&lt;?xml version=<span class="string">&quot;1.0&quot;</span> encoding=<span class="string">&quot;UTF-8&quot;</span>?&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">web-app</span> <span class="attr">xmlns</span>=<span class="string">&quot;http://xmlns.jcp.org/xml/ns/javaee&quot;</span></span></span><br><span class="line"><span class="tag">         <span class="attr">xmlns:xsi</span>=<span class="string">&quot;http://www.w3.org/2001/XMLSchema-instance&quot;</span></span></span><br><span class="line"><span class="tag">         <span class="attr">xsi:schemaLocation</span>=<span class="string">&quot;http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd&quot;</span></span></span><br><span class="line"><span class="tag">         <span class="attr">version</span>=<span class="string">&quot;4.0&quot;</span>&gt;</span></span><br><span class="line"></span><br><span class="line"><span class="comment">&lt;!--    配置SpringMVC的前端控制器DispatcherServlet</span></span><br><span class="line"><span class="comment"></span></span><br><span class="line"><span class="comment">        （以后不会吧配置文件放在这个位置下，都是放在resource下）</span></span><br><span class="line"><span class="comment">        SpringMVC的配置文件默认的位置和名称：</span></span><br><span class="line"><span class="comment">        位置：WEB-INF下</span></span><br><span class="line"><span class="comment">        名称： &lt;servlet-name&gt;-servlet.xml，当前配置下的配置文件为SpringMVC-servlet.xml</span></span><br><span class="line"><span class="comment">--&gt;</span></span><br><span class="line"></span><br><span class="line">    <span class="tag">&lt;<span class="name">servlet</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">servlet-name</span>&gt;</span>SpringMVC<span class="tag">&lt;/<span class="name">servlet-name</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">servlet-class</span>&gt;</span>org.springframework.web.servlet.DispatcherServlet<span class="tag">&lt;/<span class="name">servlet-class</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">init-param</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">param-name</span>&gt;</span>contextConfigLocation<span class="tag">&lt;/<span class="name">param-name</span>&gt;</span></span><br><span class="line">            <span class="comment">&lt;!--类路径：是指java和resources下的路径--&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">param-value</span>&gt;</span>classpath:springmvc.xml<span class="tag">&lt;/<span class="name">param-value</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;/<span class="name">init-param</span>&gt;</span></span><br><span class="line">        <span class="comment">&lt;!--将servlet初始化的时间提前到服务启动的时候，</span></span><br><span class="line"><span class="comment">            DispatcherServlet初始化的时间很久，所以非常有必要提前初始化--&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">load-on-startup</span>&gt;</span>1<span class="tag">&lt;/<span class="name">load-on-startup</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">servlet</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">servlet-mapping</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">servlet-name</span>&gt;</span>SpringMVC<span class="tag">&lt;/<span class="name">servlet-name</span>&gt;</span></span><br><span class="line">        <span class="comment">&lt;!--这里写/，匹配浏览器向服务器发送的所有请求，但是不包括以.jsp结尾的请求</span></span><br><span class="line"><span class="comment">            而/*,可以匹配.jsp的请求</span></span><br><span class="line"><span class="comment">            而DispatcherServlet不能处理这种请求，Tomcat中有专门的的处理.jsp的请求--&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">url-pattern</span>&gt;</span>/<span class="tag">&lt;/<span class="name">url-pattern</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">servlet-mapping</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">web-app</span>&gt;</span></span><br></pre></td></tr></table></figure>
<h3 id="2-3-创建请求控制器">2.3 创建请求控制器</h3>
<p>由于前端控制器对浏览器发送的请求进行了统一的处理，但是具体的请求有不同的处理过程，因此需要创建处理具体请求的类，即请求控制器</p>
<p>SpringMVC的控制器由一个POJO担任，因此需要通过@Controller注解将其标识为一个控制层组件，交给Spring的IOC容器管理。</p>
<h4 id="控制器方法匹配请求">控制器方法匹配请求</h4>
<p>斜线就代表着绝对路径，在服务器中和在浏览器中解析出来的不一样</p>
<p>在服务器中斜线被解析之后就是localhost:8080+上下文路径：<a target="_blank" rel="noopener" href="http://localhost:8080/SpringMVC/">http://localhost:8080/SpringMVC/</a></p>
<blockquote>
<p>在浏览器中，不会有上下文路径，就是http://localhost:8080/</p>
</blockquote>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@Controller</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">HelloController</span> &#123;</span><br><span class="line"></span><br><span class="line">    <span class="comment">//  在服务器中斜线代表着绝对路径</span></span><br><span class="line">    <span class="comment">// 在服务器中斜线被解析之后就是localhost:8080+上下文路径：http://localhost:8080/SpringMVC/</span></span><br><span class="line">    <span class="meta">@RequestMapping(&quot;/&quot;)</span></span><br><span class="line">    <span class="keyword">public</span> String <span class="title function_">portal</span><span class="params">()</span>&#123;</span><br><span class="line">        <span class="comment">//将逻辑视图返回，进行视图转发，加上thymeleaf中配置的前缀和后缀</span></span><br><span class="line">        <span class="keyword">return</span> <span class="string">&quot;index&quot;</span>;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@RequestMapping(&quot;/hello&quot;)</span></span><br><span class="line">    <span class="keyword">public</span> String <span class="title function_">hello</span><span class="params">()</span>&#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="string">&quot;success&quot;</span>;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<h3 id="2-4-创建SpringMVC的配置文件">2.4 创建SpringMVC的配置文件</h3>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">&lt;?xml version=<span class="string">&quot;1.0&quot;</span> encoding=<span class="string">&quot;UTF-8&quot;</span>?&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">beans</span> <span class="attr">xmlns</span>=<span class="string">&quot;http://www.springframework.org/schema/beans&quot;</span></span></span><br><span class="line"><span class="tag">       <span class="attr">xmlns:xsi</span>=<span class="string">&quot;http://www.w3.org/2001/XMLSchema-instance&quot;</span></span></span><br><span class="line"><span class="tag">       <span class="attr">xmlns:context</span>=<span class="string">&quot;http://www.springframework.org/schema/context&quot;</span></span></span><br><span class="line"><span class="tag">       <span class="attr">xsi:schemaLocation</span>=<span class="string">&quot;http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd&quot;</span>&gt;</span></span><br><span class="line"></span><br><span class="line">    <span class="comment">&lt;!--开启扫描组件--&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">context:component-scan</span> <span class="attr">base-package</span>=<span class="string">&quot;com.zylai.controller&quot;</span>/&gt;</span></span><br><span class="line"></span><br><span class="line">    <span class="comment">&lt;!-- 配置Thymeleaf视图解析器 --&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">bean</span> <span class="attr">id</span>=<span class="string">&quot;viewResolver&quot;</span></span></span><br><span class="line"><span class="tag">          <span class="attr">class</span>=<span class="string">&quot;org.thymeleaf.spring5.view.ThymeleafViewResolver&quot;</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">property</span> <span class="attr">name</span>=<span class="string">&quot;order&quot;</span> <span class="attr">value</span>=<span class="string">&quot;1&quot;</span>/&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">property</span> <span class="attr">name</span>=<span class="string">&quot;characterEncoding&quot;</span> <span class="attr">value</span>=<span class="string">&quot;UTF-8&quot;</span>/&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">property</span> <span class="attr">name</span>=<span class="string">&quot;templateEngine&quot;</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">bean</span> <span class="attr">class</span>=<span class="string">&quot;org.thymeleaf.spring5.SpringTemplateEngine&quot;</span>&gt;</span></span><br><span class="line">                <span class="tag">&lt;<span class="name">property</span> <span class="attr">name</span>=<span class="string">&quot;templateResolver&quot;</span>&gt;</span></span><br><span class="line">                    <span class="tag">&lt;<span class="name">bean</span> <span class="attr">class</span>=<span class="string">&quot;org.thymeleaf.spring5.templateresolver.SpringResourceTemplateResolver&quot;</span>&gt;</span></span><br><span class="line">                        <span class="comment">&lt;!--</span></span><br><span class="line"><span class="comment">                            物理视图路径：/WEB-INF/templates/index.html</span></span><br><span class="line"><span class="comment">                            逻辑视图：index</span></span><br><span class="line"><span class="comment">                            去掉前缀和后缀</span></span><br><span class="line"><span class="comment">                            物理视图：前缀+逻辑视图+后缀</span></span><br><span class="line"><span class="comment">                            --&gt;</span></span><br><span class="line">                        <span class="comment">&lt;!-- 视图前缀 --&gt;</span></span><br><span class="line">                        <span class="tag">&lt;<span class="name">property</span> <span class="attr">name</span>=<span class="string">&quot;prefix&quot;</span> <span class="attr">value</span>=<span class="string">&quot;/WEB-INF/templates/&quot;</span>/&gt;</span></span><br><span class="line">                        <span class="comment">&lt;!-- 视图后缀 --&gt;</span></span><br><span class="line">                        <span class="tag">&lt;<span class="name">property</span> <span class="attr">name</span>=<span class="string">&quot;suffix&quot;</span> <span class="attr">value</span>=<span class="string">&quot;.html&quot;</span>/&gt;</span></span><br><span class="line">                        <span class="tag">&lt;<span class="name">property</span> <span class="attr">name</span>=<span class="string">&quot;templateMode&quot;</span> <span class="attr">value</span>=<span class="string">&quot;HTML5&quot;</span>/&gt;</span></span><br><span class="line">                        <span class="tag">&lt;<span class="name">property</span> <span class="attr">name</span>=<span class="string">&quot;characterEncoding&quot;</span> <span class="attr">value</span>=<span class="string">&quot;UTF-8&quot;</span> /&gt;</span></span><br><span class="line">                    <span class="tag">&lt;/<span class="name">bean</span>&gt;</span></span><br><span class="line">                <span class="tag">&lt;/<span class="name">property</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;/<span class="name">bean</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;/<span class="name">property</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">bean</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">beans</span>&gt;</span></span><br></pre></td></tr></table></figure>
<h3 id="2-5-请求访问页面和跳转页面">2.5 请求访问页面和跳转页面</h3>
<h4 id="2-5-1-创建的位置">2.5.1 创建的位置</h4>
<p>在<code>/WEB-INF/templates/</code>创建index.html</p>
<p><strong>注意：浏览器无法直接访问WEB-INF下的资源，只能通过服务器访问</strong></p>
<h4 id="2-5-2-访问页面">2.5.2 访问页面</h4>
<ol>
<li>在前端控制器中具体的方法返回逻辑视图的名称，比如返回<code>index</code></li>
<li>thymeleaf视图解析器会解析逻辑视图，加上前缀<code>/WEB-INF/templates/</code>和后缀<code>.html</code></li>
<li>最后根据总的完整路径<code>/WEB-INF/templates/index.html</code>进行转发</li>
<li>转发到index.html页面，thymeleaf先回渲染这个页面中的thymeleaf表达式</li>
</ol>
<h4 id="2-5-3-页面中的路径解析">2.5.3 页面中的路径解析</h4>
<p>浏览器会解析为绝对路径，localhost:8080/hello</p>
<figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">&lt;!--使用thymeleaf解析，拼接上上下文路径，最后路径为localhost:8080/SpringMVC/hello--&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">a</span> <span class="attr">th:href</span>=<span class="string">&quot;@&#123;/hello&#125;&quot;</span>&gt;</span>测试SpringMVC<span class="tag">&lt;/<span class="name">a</span>&gt;</span></span><br><span class="line"></span><br><span class="line"><span class="comment">&lt;!--这里斜线是绝对路径，是浏览器解析的，会被解析为 localhost:8080/hello--&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">a</span> <span class="attr">href</span>=<span class="string">&quot;/hello&quot;</span>&gt;</span>测试绝对路径<span class="tag">&lt;/<span class="name">a</span>&gt;</span></span><br></pre></td></tr></table></figure>
<h3 id="总结">总结</h3>
<p>流程：</p>
<ol>
<li>浏览器发送请求</li>
<li>若请求地址符合前端控制器DispatcherServlet中url-pattern，该请求就会被DispatcherServlet处理</li>
<li>前端控制器会读取SpringMVC的核心配置文件，通过扫描组件找到控制器controller</li>
<li>将请求地址和控制器中方法上的@RequestMapping注解的value属性值进行匹配，匹配成功就会执行对应的方法</li>
<li>方法会返回一个字符串类型的视图名称，比如返回<code>index</code>，是逻辑地址。thymeleaf视图解析器会解析逻辑视图，加上前缀<code>/WEB-INF/templates/</code>和后缀<code>.html</code></li>
<li>根据总的完整路径<code>/WEB-INF/templates/index.html</code>进行转发，转发到index.html页面，thymeleaf先回渲染这个页面中的thymeleaf表达式</li>
</ol>
<h2 id="3-RequestMapping注解🚀">3 RequestMapping注解🚀</h2>
<h3 id="3-1-标识的位置">3.1 标识的位置</h3>
<p>@RequestMapping标识一个类：设置映射请求的请求路径的初始信息</p>
<p>@RequestMapping标识一个方法：设置映射请求请求路径的具体信息</p>
<p>即，类上的路径加上方法上的路径</p>
<h3 id="3-2-value属性⭐">3.2 value属性⭐</h3>
<p>作用：通过请求的请求路径匹配请求</p>
<p>value属性是数组类型，即当前浏览器所发送请求的路径匹配value属性中的任何一个值，则当前请求就会被这个控制器方法进行处理</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@RequestMapping(value = &#123;&quot;/hello&quot;,&quot;/abc&quot;&#125;)</span></span><br><span class="line"><span class="keyword">public</span> String <span class="title function_">hello</span><span class="params">()</span>&#123;</span><br><span class="line">    <span class="keyword">return</span> <span class="string">&quot;success&quot;</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">a</span> <span class="attr">th:href</span>=<span class="string">&quot;@&#123;/abc&#125;&quot;</span>&gt;</span>测试@RequestMapping注解的value属性<span class="tag">&lt;/<span class="name">a</span>&gt;</span></span><br></pre></td></tr></table></figure>
<h3 id="3-3-method属性⭐">3.3 method属性⭐</h3>
<p>作用：通过请求的请求方式匹配请求</p>
<p>method属性是<strong>RequestMethod类型</strong>的数组，即若当前浏览器所发送请求的请求方式匹配method属性数组中的任何一种请求方式，则当前请求就会被注解所标识的方法进行处理</p>
<p>若浏览器所发送的请求的路径和value属性匹配，但是请求方式不匹配，则页面报错：HTTP状态 405 - 方法不允许</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@RequestMapping(</span></span><br><span class="line"><span class="meta">        value = &#123;&quot;/hello&quot;,&quot;/abc&quot;&#125;,</span></span><br><span class="line"><span class="meta">        method = &#123;RequestMethod.POST,RequestMethod.GET&#125;</span></span><br><span class="line"><span class="meta">        )</span></span><br><span class="line"><span class="keyword">public</span> String <span class="title function_">hello</span><span class="params">()</span>&#123;</span><br><span class="line">    <span class="keyword">return</span> <span class="string">&quot;success&quot;</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>如果不指定method属性，<strong>那就可以匹配任意类型的请求</strong></p>
<h3 id="3-4-params属性（了解）">3.4 params属性（了解）</h3>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">* 作用：通过请求的请求参数匹配请求，即浏览器发送的请求的请求参数必须满足params属性的设置</span><br><span class="line">* 可以使用四种表达式：</span><br><span class="line">* &quot;param&quot;：表示当前所匹配请求的请求参数中必须携带param参数，不管他的值是啥</span><br><span class="line">* &quot;!param&quot;：表示当前所匹配请求的请求参数中一定不能携带param参数</span><br><span class="line">* &quot;param=value&quot;：表示当前所匹配请求的请求参数中必须携带param参数且值必须为value</span><br><span class="line">* &quot;param!=value&quot;：表示当前所匹配请求的请求参数中可以不携带param参数，若携带，值一定不等于value</span><br><span class="line">*</span><br></pre></td></tr></table></figure>
<h3 id="3-5-headers属性（了解）">3.5 headers属性（了解）</h3>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">* 作用：通过请求的请求头匹配请求，即浏览器发送的请求的请求头必须满足headers属性的设置</span><br><span class="line">* &quot;header&quot;：要求请求映射所匹配的请求必须携带header请求头信息</span><br><span class="line">* &quot;!header&quot;：要求请求映射所匹配的请求必须不能携带header请求头信息</span><br><span class="line">* &quot;header=value&quot;：要求请求映射所匹配的请求必须携带header请求头信息且header=value</span><br><span class="line">* &quot;header!=value&quot;：要求请求映射所匹配的请求必须携带header请求头信息且header!=value</span><br><span class="line">* 注意：若当前请求满足@RequestMapping注解的value和method属性，但是不满足headers属性，</span><br><span class="line">* 此时页面显示404错误，即资源未找到</span><br></pre></td></tr></table></figure>
<h3 id="3-6-SpringMVC支持ant风格的路径">3.6 SpringMVC支持ant风格的路径</h3>
<p>在@RequestMapping注解的value属性中设置一些特殊字符<br>
<code>?</code>：任意的单个字符(不包括?和/)<br>
<code>*</code>：表示0个或多个任意字符(不包括?和/)<br>
<code>**</code>：表示任意层数的任意目录，注意使用方式只能将<code>**</code> 写在双斜线中，前后不能有任何的其他字符</p>
<h3 id="3-7-使用路径中的占位符（重点）🌟">3.7 使用路径中的占位符（重点）🌟</h3>
<p>对比：</p>
<ul>
<li>传统：/deleteUser?id=1</li>
<li>rest: /deleteUser/1</li>
</ul>
<p>使用：</p>
<p>需要在@RequestMapping注解的value属性中所设置的路径中，使用{xxx}的方式表示路径中的数据</p>
<p>再通过@PathVariable注解，将占位符的值和控制器方法的形参进行绑定</p>
<figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">a</span> <span class="attr">th:href</span>=<span class="string">&quot;@&#123;/test/rest/2374234/admin&#125;&quot;</span>&gt;</span>测试value属性中的占位符<span class="tag">&lt;/<span class="name">a</span>&gt;</span></span><br></pre></td></tr></table></figure>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@RequestMapping(&quot;/test/rest/&#123;id&#125;/&#123;username&#125;&quot;)</span></span><br><span class="line"><span class="keyword">public</span> String <span class="title function_">testRest</span><span class="params">(<span class="meta">@PathVariable(value = &quot;id&quot;)</span> Integer id,<span class="meta">@PathVariable(value = &quot;username&quot;)</span>String username)</span>&#123;</span><br><span class="line"></span><br><span class="line">    System.out.println(<span class="string">&quot;id:&quot;</span>+id+<span class="string">&quot;,username:&quot;</span>+username);</span><br><span class="line">    <span class="keyword">return</span> <span class="string">&quot;success&quot;</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">11:01:50.534 [http-nio-8080-exec-4] DEBUG org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping - Mapped to com.zylai.controller.TestRequestMappingController#testRest(Integer, String)</span><br><span class="line">id:2374234,username:admin</span><br></pre></td></tr></table></figure>
<h2 id="4-SpringMVC获取请求参数📟">4 SpringMVC获取请求参数📟</h2>
<h3 id="4-1-通过servletAPI获取">4.1 通过servletAPI获取</h3>
<blockquote>
<p>很少用</p>
</blockquote>
<p>只需要在控制其方法的形参位置设置HttpServletRequest类型的形参，就可以在控制器方法中使用request对象获取请求参数。</p>
<p><strong>这里DispatcherServlet会根据request参数去匹配，会把request对象传过来（具体实现可以参考JavaWeb中的myssm实现）</strong></p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line">    <span class="meta">@RequestMapping(&quot;/servletapi&quot;)</span></span><br><span class="line"><span class="comment">//    直接在参数中写HttpServletRequest即可，DispatcherServlet会根据参数去匹配</span></span><br><span class="line">    <span class="keyword">public</span> String <span class="title function_">getParamByServletAPI</span><span class="params">(HttpServletRequest request)</span>&#123;</span><br><span class="line"></span><br><span class="line">        <span class="type">String</span> <span class="variable">username</span> <span class="operator">=</span> request.getParameter(<span class="string">&quot;username&quot;</span>);</span><br><span class="line">        <span class="type">String</span> <span class="variable">password</span> <span class="operator">=</span> request.getParameter(<span class="string">&quot;password&quot;</span>);</span><br><span class="line">        System.out.println(<span class="string">&quot;username:&quot;</span>+username+<span class="string">&quot;,password:&quot;</span>+password);</span><br><span class="line">        <span class="keyword">return</span> <span class="string">&quot;success&quot;</span>;</span><br><span class="line">    &#125;</span><br></pre></td></tr></table></figure>
<h3 id="4-2-通过控制器方法的形参获取">4.2 通过控制器方法的形参获取</h3>
<p>只需要在控制器方法的形参位置设置好形参，其名字和请求参数的名字一致即可。</p>
<p>表单：</p>
<figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">form</span> <span class="attr">th:action</span>=<span class="string">&quot;@&#123;/param/params&#125;&quot;</span> <span class="attr">method</span>=<span class="string">&quot;post&quot;</span>&gt;</span></span><br><span class="line">    用户名：<span class="tag">&lt;<span class="name">input</span> <span class="attr">type</span>=<span class="string">&quot;text&quot;</span> <span class="attr">name</span>=<span class="string">&quot;username&quot;</span>&gt;</span><span class="tag">&lt;<span class="name">br</span>/&gt;</span></span><br><span class="line">    密码：<span class="tag">&lt;<span class="name">input</span> <span class="attr">type</span>=<span class="string">&quot;password&quot;</span> <span class="attr">name</span>=<span class="string">&quot;password&quot;</span>&gt;</span><span class="tag">&lt;<span class="name">br</span>/&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">input</span> <span class="attr">type</span>=<span class="string">&quot;submit&quot;</span> <span class="attr">value</span>=<span class="string">&quot;登录&quot;</span>&gt;</span><span class="tag">&lt;<span class="name">br</span>/&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">form</span>&gt;</span></span><br></pre></td></tr></table></figure>
<p>控制器方法：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@RequestMapping(&quot;/params&quot;)</span></span><br><span class="line"><span class="keyword">public</span> String <span class="title function_">getParams</span><span class="params">(String username,String password)</span>&#123;</span><br><span class="line"> System.out.println(<span class="string">&quot;username:&quot;</span>+username+<span class="string">&quot;,password:&quot;</span>+password);</span><br><span class="line">    <span class="keyword">return</span> <span class="string">&quot;success&quot;</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<h3 id="4-3-RequestParam注解🌊">4.3 @RequestParam注解🌊</h3>
<p>将请求参数和控制器方法的形参绑定，三个属性为：</p>
<ul>
<li>value：设置和形参绑定的请求参数的名字</li>
<li>required：设置是否必须传输value设置的请求参数，默认值为true，表示必须传输，否则报错400</li>
<li>defaultValue：当未传输value对应的请求参数时，为形参设置默认值，此时和required的值无关</li>
</ul>
<p>比如，这里把username改为userName，和控制器方法的形参名字<strong>不一致</strong></p>
<figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">form</span> <span class="attr">th:action</span>=<span class="string">&quot;@&#123;/param/params&#125;&quot;</span> <span class="attr">method</span>=<span class="string">&quot;post&quot;</span>&gt;</span></span><br><span class="line">    用户名：<span class="tag">&lt;<span class="name">input</span> <span class="attr">type</span>=<span class="string">&quot;text&quot;</span> <span class="attr">name</span>=<span class="string">&quot;userName&quot;</span>&gt;</span><span class="tag">&lt;<span class="name">br</span>/&gt;</span></span><br><span class="line">    密码：<span class="tag">&lt;<span class="name">input</span> <span class="attr">type</span>=<span class="string">&quot;password&quot;</span> <span class="attr">name</span>=<span class="string">&quot;password&quot;</span>&gt;</span><span class="tag">&lt;<span class="name">br</span>/&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">input</span> <span class="attr">type</span>=<span class="string">&quot;submit&quot;</span> <span class="attr">value</span>=<span class="string">&quot;登录&quot;</span>&gt;</span><span class="tag">&lt;<span class="name">br</span>/&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">form</span>&gt;</span></span><br></pre></td></tr></table></figure>
<p>这时只需要在控制器方法的形参上加上注解即可。</p>
<blockquote>
<p>实际中，一般只用到value这一个属性就行，这里为了演示</p>
</blockquote>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@RequestMapping(&quot;/params&quot;)</span></span><br><span class="line"><span class="keyword">public</span> String <span class="title function_">getParams</span><span class="params">( <span class="meta">@RequestParam(value = &quot;userName&quot;,required = false,defaultValue = &quot;hello&quot;)</span> String username, String password)</span>&#123;</span><br><span class="line"> System.out.println(<span class="string">&quot;username:&quot;</span>+username+<span class="string">&quot;,password:&quot;</span>+password);</span><br><span class="line">    <span class="keyword">return</span> <span class="string">&quot;success&quot;</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<h3 id="4-4-RequestHeader注解">4.4 @RequestHeader注解</h3>
<p>参考@RequestParam注解，这里是获取请求头</p>
<h3 id="4-5-CookieValue注解">4.5 @CookieValue注解</h3>
<p>参考@RequestParam注解，这里是根据名称获取cookie</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@RequestMapping(&quot;/params&quot;)</span></span><br><span class="line"><span class="keyword">public</span> String <span class="title function_">getParams</span><span class="params">(</span></span><br><span class="line"><span class="params">        <span class="meta">@RequestParam(value = &quot;userName&quot;,required = false,defaultValue = &quot;hello&quot;)</span> String username,</span></span><br><span class="line"><span class="params">        String password,</span></span><br><span class="line"><span class="params">        <span class="meta">@RequestHeader(&quot;referer&quot;)</span> String referer,</span></span><br><span class="line"><span class="params">        <span class="meta">@CookieValue(&quot;JSESSIONID&quot;)</span> String jsessionId)</span>&#123;</span><br><span class="line">    System.out.println(<span class="string">&quot;username:&quot;</span>+username+<span class="string">&quot;,password:&quot;</span>+password);</span><br><span class="line">    System.out.println(<span class="string">&quot;referer:&quot;</span>+referer+<span class="string">&quot;\ncookie-jsessionId:&quot;</span>+jsessionId);</span><br><span class="line">    <span class="keyword">return</span> <span class="string">&quot;success&quot;</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<h3 id="4-6-通过控制器方法的实体类类型的形参获取✌️">4.6 通过控制器方法的实体类类型的形参获取✌️</h3>
<p>需要保证<strong>实体类中的属性的属性名和请求参数的名字一致</strong>，才可以通过实体类类型的形参获取请求参数。</p>
<p>实体类User：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">User</span> &#123;</span><br><span class="line">    <span class="keyword">private</span>  Integer id;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">private</span> String username;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">private</span> String password;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>表单：</p>
<figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">form</span> <span class="attr">th:action</span>=<span class="string">&quot;@&#123;/param/pojo&#125;&quot;</span> <span class="attr">method</span>=<span class="string">&quot;post&quot;</span>&gt;</span></span><br><span class="line">    用户名：<span class="tag">&lt;<span class="name">input</span> <span class="attr">type</span>=<span class="string">&quot;text&quot;</span> <span class="attr">name</span>=<span class="string">&quot;userName&quot;</span>&gt;</span><span class="tag">&lt;<span class="name">br</span>/&gt;</span></span><br><span class="line">    密码：<span class="tag">&lt;<span class="name">input</span> <span class="attr">type</span>=<span class="string">&quot;password&quot;</span> <span class="attr">name</span>=<span class="string">&quot;password&quot;</span>&gt;</span><span class="tag">&lt;<span class="name">br</span>/&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">input</span> <span class="attr">type</span>=<span class="string">&quot;submit&quot;</span> <span class="attr">value</span>=<span class="string">&quot;登录&quot;</span>&gt;</span><span class="tag">&lt;<span class="name">br</span>/&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">form</span>&gt;</span></span><br></pre></td></tr></table></figure>
<p>控制器方法：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@RequestMapping(&quot;/pojo&quot;)</span></span><br><span class="line"><span class="keyword">public</span> String <span class="title function_">getParamByPojo</span><span class="params">(User user)</span>&#123;</span><br><span class="line">    System.out.println(user);</span><br><span class="line">    <span class="keyword">return</span> <span class="string">&quot;success&quot;</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<h3 id="4-7-设置编码-🏮">4.7 设置编码 🏮</h3>
<h4 id="在web-xml中设置">在<code>web.xml</code>中设置</h4>
<p>设置两个属性<code>encoding</code>和<code>forceEncoding</code></p>
<blockquote>
<p>注意：在SpringMVC中，编码过滤器一定配置到其他过滤器之前</p>
</blockquote>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">&lt;!--配置SpringMVC的编码过滤器--&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">filter</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">filter-name</span>&gt;</span>CharacterEncodingFilter<span class="tag">&lt;/<span class="name">filter-name</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">filter-class</span>&gt;</span>org.springframework.web.filter.CharacterEncodingFilter<span class="tag">&lt;/<span class="name">filter-class</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">init-param</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">param-name</span>&gt;</span>encoding<span class="tag">&lt;/<span class="name">param-name</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">param-value</span>&gt;</span>UTF-8<span class="tag">&lt;/<span class="name">param-value</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">init-param</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">init-param</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">param-name</span>&gt;</span>forceEncoding<span class="tag">&lt;/<span class="name">param-name</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">param-value</span>&gt;</span>true<span class="tag">&lt;/<span class="name">param-value</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">init-param</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">filter</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">filter-mapping</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">filter-name</span>&gt;</span>CharacterEncodingFilter<span class="tag">&lt;/<span class="name">filter-name</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">url-pattern</span>&gt;</span>/*<span class="tag">&lt;/<span class="name">url-pattern</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">filter-mapping</span>&gt;</span></span><br></pre></td></tr></table></figure>
<h4 id="源码解析">源码解析</h4>
<blockquote>
<p>这是倒着的关系。CharacterEncodingFilter中设置编码的方法是doFilterInternal。CharacterEncodingFilter的父类OncePerRequestFilter重写了doFilter方法，在doFilter方法中，调用了设置编码的方法doFilterInternal</p>
</blockquote>
<p><img src="https://zylai-cloud-pic-1306915061.cos.ap-nanjing.myqcloud.com/images01/SpringMVC.assets/image-20220729154853195.png" alt="image-20220729154853195"></p>
<p>调用这个构造器</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="title function_">CharacterEncodingFilter</span><span class="params">(String encoding, <span class="type">boolean</span> forceEncoding)</span> &#123;</span><br><span class="line">   <span class="built_in">this</span>(encoding, forceEncoding, forceEncoding);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>this用三个参数的构造器，给三个成员变量赋值</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="title function_">CharacterEncodingFilter</span><span class="params">(String encoding, <span class="type">boolean</span> forceRequestEncoding, <span class="type">boolean</span> forceResponseEncoding)</span> &#123;</span><br><span class="line">   Assert.hasLength(encoding, <span class="string">&quot;Encoding must not be empty&quot;</span>);</span><br><span class="line">   <span class="built_in">this</span>.encoding = encoding;</span><br><span class="line">   <span class="built_in">this</span>.forceRequestEncoding = forceRequestEncoding;</span><br><span class="line">   <span class="built_in">this</span>.forceResponseEncoding = forceResponseEncoding;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>在这个方法中，设置request和response的参数</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@Override</span></span><br><span class="line"><span class="keyword">protected</span> <span class="keyword">void</span> <span class="title function_">doFilterInternal</span><span class="params">(</span></span><br><span class="line"><span class="params">      HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)</span></span><br><span class="line">      <span class="keyword">throws</span> ServletException, IOException &#123;</span><br><span class="line"></span><br><span class="line">   <span class="type">String</span> <span class="variable">encoding</span> <span class="operator">=</span> getEncoding();</span><br><span class="line">   <span class="keyword">if</span> (encoding != <span class="literal">null</span>) &#123;</span><br><span class="line">      <span class="keyword">if</span> (isForceRequestEncoding() || request.getCharacterEncoding() == <span class="literal">null</span>) &#123;</span><br><span class="line">         request.setCharacterEncoding(encoding);</span><br><span class="line">      &#125;</span><br><span class="line">      <span class="keyword">if</span> (isForceResponseEncoding()) &#123;</span><br><span class="line">         response.setCharacterEncoding(encoding);</span><br><span class="line">      &#125;</span><br><span class="line">   &#125;</span><br><span class="line">   filterChain.doFilter(request, response);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<h2 id="5-域对象共享数据🥘">5 域对象共享数据🥘</h2>
<p>SpringMVC往域对象中共享数据，最终都是通过ModelAndView实现</p>
<h3 id="5-1-通过ModelAndView向请求域共享数据">5.1 通过ModelAndView向请求域共享数据</h3>
<ul>
<li>用其Model功能向请求域中共享数据</li>
<li>使用View功能设置逻辑视图，但是控制器方法一定要将ModelAndView作为方法的返回值</li>
</ul>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@RequestMapping(&quot;/test/mav&quot;)</span></span><br><span class="line"><span class="keyword">public</span> ModelAndView <span class="title function_">testMAV</span><span class="params">()</span>&#123;</span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * ModelAndView包含Model和View的功能</span></span><br><span class="line"><span class="comment">     * Model：向请求域中共享数据</span></span><br><span class="line"><span class="comment">     * View：设置逻辑视图实现页面跳转</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="type">ModelAndView</span> <span class="variable">mav</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">ModelAndView</span>();</span><br><span class="line">    <span class="comment">//向请求域中设置数据</span></span><br><span class="line">    mav.addObject(<span class="string">&quot;testRequestScope&quot;</span>,<span class="string">&quot;hello,ModelAndView&quot;</span>);</span><br><span class="line">    <span class="comment">//设置视图名称</span></span><br><span class="line">    mav.setViewName(<span class="string">&quot;success&quot;</span>);</span><br><span class="line">    <span class="keyword">return</span> mav;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<h3 id="5-2-通过Model向请求域共享数据">5.2 通过Model向请求域共享数据</h3>
<blockquote>
<p>注意：5.2 5.3  5.4 这三个选择一个用就可以，一般选择Model</p>
</blockquote>
<p>将Model作为方法的形参，之后设置域共享数据即可</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@RequestMapping(&quot;/test/model&quot;)</span></span><br><span class="line"><span class="keyword">public</span> String <span class="title function_">testModel</span><span class="params">(Model model)</span>&#123;</span><br><span class="line">    System.out.println(model.getClass().getName());</span><br><span class="line">    <span class="comment">//org.springframework.validation.support.BindingAwareModelMap</span></span><br><span class="line">    model.addAttribute(<span class="string">&quot;testRequestScope&quot;</span>,<span class="string">&quot;hello,Model&quot;</span>);</span><br><span class="line">    <span class="keyword">return</span> <span class="string">&quot;success&quot;</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<h3 id="5-3-通过ModelMap向请求域共享数据">5.3 通过ModelMap向请求域共享数据</h3>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@RequestMapping(&quot;/test/modelMap&quot;)</span></span><br><span class="line"><span class="keyword">public</span> String <span class="title function_">testModel</span><span class="params">(ModelMap modelMap)</span>&#123;</span><br><span class="line">    System.out.println(modelMap.getClass().getName());</span><br><span class="line">    <span class="comment">//org.springframework.validation.support.BindingAwareModelMap</span></span><br><span class="line">    modelMap.addAttribute(<span class="string">&quot;testRequestScope&quot;</span>,<span class="string">&quot;hello,ModelMap&quot;</span>);</span><br><span class="line">    <span class="keyword">return</span> <span class="string">&quot;success&quot;</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<h3 id="5-4-通过Map向请求域共享数据">5.4 通过Map向请求域共享数据</h3>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@RequestMapping(&quot;/test/map&quot;)</span></span><br><span class="line"><span class="keyword">public</span> String <span class="title function_">testMap</span><span class="params">(Map&lt;String,Object&gt; map)</span>&#123;</span><br><span class="line">    System.out.println(map.getClass().getName());</span><br><span class="line">    <span class="comment">//org.springframework.validation.support.BindingAwareModelMap</span></span><br><span class="line">    map.put(<span class="string">&quot;testRequestScope&quot;</span>,<span class="string">&quot;hello,Map&quot;</span>);</span><br><span class="line">    <span class="keyword">return</span> <span class="string">&quot;success&quot;</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<h3 id="5-5-Model和ModelMap和Map的关系">5.5 Model和ModelMap和Map的关系</h3>
<p>其实在底层中，这些类型的形参最终都是通过<code>BindingAwareModelMap</code>创建的</p>
<p>几个类的关系：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">BindingAwareModelMap</span> <span class="keyword">extends</span> <span class="title class_">ExtendedModelMap</span> &#123;&#125;</span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">ExtendedModelMap</span> <span class="keyword">extends</span> <span class="title class_">ModelMap</span> <span class="keyword">implements</span> <span class="title class_">Model</span> &#123;&#125;</span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">ModelMap</span> <span class="keyword">extends</span> <span class="title class_">LinkedHashMap</span>&lt;String, Object&gt; &#123;&#125;</span><br></pre></td></tr></table></figure>
<p><img src="https://zylai-cloud-pic-1306915061.cos.ap-nanjing.myqcloud.com/images01/SpringMVC.assets/image-20220729170924654.png" alt="image-20220729170924654"></p>
<p>最终都是返回一个ModelAndView实例</p>
<p><img src="https://zylai-cloud-pic-1306915061.cos.ap-nanjing.myqcloud.com/images01/SpringMVC.assets/image-20220729174045137.png" alt="image-20220729174045137"></p>
<h3 id="5-6-共享session域和application域中的数据">5.6 共享session域和application域中的数据</h3>
<p>使用servletAPI即可</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@RequestMapping(&quot;/test/session&quot;)</span></span><br><span class="line"><span class="keyword">public</span> String <span class="title function_">testSession</span><span class="params">(HttpSession session)</span>&#123;</span><br><span class="line">    session.setAttribute(<span class="string">&quot;testSessionScope&quot;</span>,<span class="string">&quot;hello,session&quot;</span>);</span><br><span class="line">    <span class="keyword">return</span> <span class="string">&quot;success&quot;</span>;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="meta">@RequestMapping(&quot;/test/application&quot;)</span></span><br><span class="line"><span class="keyword">public</span> String <span class="title function_">testApplication</span><span class="params">(HttpSession session)</span>&#123;</span><br><span class="line">    <span class="type">ServletContext</span> <span class="variable">application</span> <span class="operator">=</span> session.getServletContext();</span><br><span class="line">    application.setAttribute(<span class="string">&quot;testApplicationScope&quot;</span>,<span class="string">&quot;hello,application&quot;</span>);</span><br><span class="line">    <span class="keyword">return</span> <span class="string">&quot;success&quot;</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<h2 id="6-SpringMVC视图🌅">6 SpringMVC视图🌅</h2>
<p>SpringMVC中的视图是View接口，视图的作用渲染数据，将模型Model中的数据展示给用户</p>
<p>SpringMVC视图的种类很多，默认有转发视图InternalResourceView和重定向视图RedirectView</p>
<p>当工程引入jstl的依赖，转发视图会自动转换为JstlView</p>
<p>若使用的视图技术为Thymeleaf，在SpringMVC的配置文件中配置了Thymeleaf的视图解析器，由此视图解析器解析之后所得到的是ThymeleafView</p>
<h3 id="6-1-Thymeleaf视图">6.1 Thymeleaf视图</h3>
<p>当控制器方法中所设置的<strong>视图名称没有任何前缀时</strong>，此时的视图名称会被SpringMVC配置文件中所配置的视图解析器解析，视图名称拼接视图前缀和视图后缀所得到的最终路径，会通过转发的方式实现跳转</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@RequestMapping(&quot;/testHello&quot;)</span></span><br><span class="line"><span class="keyword">public</span> String <span class="title function_">testHello</span><span class="params">()</span>&#123;</span><br><span class="line">    <span class="keyword">return</span> <span class="string">&quot;hello&quot;</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p><img src="https://zylai-cloud-pic-1306915061.cos.ap-nanjing.myqcloud.com/images01/SpringMVC.assets/image-20220729200023623.png" alt="image-20220729200023623"></p>
<h3 id="6-2-转发视图">6.2 转发视图</h3>
<p>转发和重定向：</p>
<ol>
<li>转发浏览器发送一次请求，在服务器中处理一次，重定向浏览器发送两次请求。</li>
<li>转发由于只发送一次请求，地址栏地址不变。重定向改变</li>
<li>转发由于只发送一次request请求，可以使用request共享域中的数据，而重定向不可</li>
</ol>
<p>SpringMVC中默认的转发视图是InternalResourceView</p>
<p>SpringMVC中创建转发视图的情况：</p>
<p>当控制器方法中所设置的视图名称以&quot;forward:&quot;为前缀时，创建InternalResourceView视图，此时的视图名称不会被SpringMVC配置文件中所配置的视图解析器解析，而是会将前缀&quot;forward:&quot;去掉，剩余部分作为最终路径通过转发的方式实现跳转。</p>
<p>例如&quot;forward:/&quot;，“forward:/employee”。</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@RequestMapping(&quot;/testForward&quot;)</span></span><br><span class="line"><span class="keyword">public</span> String <span class="title function_">testForward</span><span class="params">()</span>&#123;</span><br><span class="line">    <span class="keyword">return</span> <span class="string">&quot;forward:/testHello&quot;</span>;<span class="comment">//跳转到路径为/testHello的控制器方法中，之后再执行这个方法</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p><img src="https://zylai-cloud-pic-1306915061.cos.ap-nanjing.myqcloud.com/images01/SpringMVC.assets/image-20220729200138481.png" alt="image-20220729200138481"></p>
<h3 id="6-3-重定向视图">6.3 重定向视图</h3>
<p>SpringMVC中默认的重定向视图是RedirectView</p>
<p>当控制器方法中所设置的视图名称以&quot;redirect:&quot;为前缀时，创建RedirectView视图，此时的视图名称不会被SpringMVC配置文件中所配置的视图解析器解析，而是会将前缀&quot;redirect:&quot;去掉，剩余部分作为最终路径通过重定向的方式实现跳转</p>
<p>例如&quot;redirect:/&quot;，“redirect:/employee”</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@RequestMapping(&quot;/testRedirect&quot;)</span></span><br><span class="line"><span class="keyword">public</span> String <span class="title function_">testRedirect</span><span class="params">()</span>&#123;</span><br><span class="line">    <span class="keyword">return</span> <span class="string">&quot;redirect:/testHello&quot;</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p><img src="https://zylai-cloud-pic-1306915061.cos.ap-nanjing.myqcloud.com/images01/SpringMVC.assets/image-20220729200147432.png" alt="image-20220729200147432"></p>
<h3 id="6-4-视图控制器">6.4 视图控制器</h3>
<p>当控制器方法中，仅仅用来实现页面跳转，即只需要设置视图名称时，可以将处理器方法使用viewcontroller标签进行表示。</p>
<p>注意：<br>
当SpringMVC中设置任何一个view-controller时，其他控制器中的请求映射将全部失效，此时需<br>
要在SpringMVC的核心配置文件中设置开启mvc注解驱动的标签：<br>
&lt;mvc:annotation-driven /&gt;</p>
<h2 id="7-RESTful😪">7 RESTful😪</h2>
<h3 id="7-1-RESTful简介">7.1 RESTful简介</h3>
<p>将服务器看做由很多资源组成，一切皆资源。对于同一个资源，要求其访问路径是一样的，不论是增删改查，路径都是一样。</p>
<p>但是如何区别增删改查呢？使用请求方式修改。</p>
<blockquote>
<p>下面是比较详细的介绍</p>
</blockquote>
<p><img src="https://zylai-cloud-pic-1306915061.cos.ap-nanjing.myqcloud.com/images01/SpringMVC.assets/image-20220730111356174.png" alt="image-20220730111356174"></p>
<h3 id="7-2-RESTful的实现">7.2 RESTful的实现</h3>
<p>具体说，就是 HTTP 协议里面，四个表示操作方式的动词：GET、POST、PUT、DELETE。它们分别对应四种基本操作：GET 用来获取资源，POST 用来新建资源，PUT 用来更新资源，DELETE用来删除资源。</p>
<p>REST 风格提倡 URL 地址使用统一的风格设计，从前到后各个单词使用斜杠分开，不使用问号键值对方式携带请求参数，而是将要发送给服务器的数据作为 URL 地址的一部分，以保证整体风格的一致性。</p>
<p>以操作用户对象为例：</p>
<p><img src="https://zylai-cloud-pic-1306915061.cos.ap-nanjing.myqcloud.com/images01/SpringMVC.assets/image-20220730111553310.png" alt="image-20220730111553310"></p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@Controller</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">TestRestController</span> &#123;</span><br><span class="line"></span><br><span class="line"><span class="comment">//    @RequestMapping(value = &quot;/user&quot;,method = RequestMethod.GET)</span></span><br><span class="line">    <span class="meta">@GetMapping(&quot;/user&quot;)</span></span><br><span class="line">    <span class="keyword">public</span> String <span class="title function_">getAllUser</span><span class="params">()</span>&#123;</span><br><span class="line">        System.out.println(<span class="string">&quot;查询所有的用户信息--&gt;/user--&gt;get&quot;</span>);</span><br><span class="line">        <span class="keyword">return</span> <span class="string">&quot;success&quot;</span>;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">//    @RequestMapping(value = &quot;/user/&#123;id&#125;&quot;,method = RequestMethod.GET)</span></span><br><span class="line">    <span class="meta">@GetMapping(&quot;/user/&#123;id&#125;&quot;)</span></span><br><span class="line">    <span class="keyword">public</span> String <span class="title function_">getUserById</span><span class="params">(<span class="meta">@PathVariable(&quot;id&quot;)</span>Integer id)</span>&#123;</span><br><span class="line">        System.out.println(<span class="string">&quot;根据id查询用户信息--&gt;/user/&quot;</span>+id+<span class="string">&quot;--&gt;get&quot;</span>);</span><br><span class="line">        <span class="keyword">return</span> <span class="string">&quot;success&quot;</span>;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment">//    @RequestMapping(value = &quot;/user&quot;,method = RequestMethod.POST)</span></span><br><span class="line">    <span class="meta">@PostMapping(&quot;/user&quot;)</span></span><br><span class="line">    <span class="keyword">public</span> String <span class="title function_">insertUser</span><span class="params">()</span>&#123;</span><br><span class="line">        System.out.println(<span class="string">&quot;添加用户信息--&gt;/user--&gt;post&quot;</span>);</span><br><span class="line">        <span class="keyword">return</span> <span class="string">&quot;success&quot;</span>;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">//    @RequestMapping(value = &quot;/user&quot;,method = RequestMethod.PUT)</span></span><br><span class="line">    <span class="meta">@PutMapping(&quot;/user&quot;)</span></span><br><span class="line">    <span class="keyword">public</span> String <span class="title function_">updateUser</span><span class="params">()</span>&#123;</span><br><span class="line">        System.out.println(<span class="string">&quot;修改用户信息--&gt;/user--&gt;put&quot;</span>);</span><br><span class="line">        <span class="keyword">return</span> <span class="string">&quot;success&quot;</span>;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">//    @RequestMapping(value = &quot;/user/&#123;id&#125;&quot;,method = RequestMethod.DELETE)</span></span><br><span class="line">    <span class="meta">@DeleteMapping(&quot;/user/&#123;id&#125;&quot;)</span></span><br><span class="line">    <span class="keyword">public</span> String <span class="title function_">updateUser</span><span class="params">(<span class="meta">@PathVariable(&quot;id&quot;)</span> Integer id)</span>&#123;</span><br><span class="line">        System.out.println(<span class="string">&quot;删除用户信息--&gt;/user/&quot;</span>+id+<span class="string">&quot;--&gt;delete&quot;</span>);</span><br><span class="line">        <span class="keyword">return</span> <span class="string">&quot;success&quot;</span>;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<h3 id="7-3-处理PUT和DELETE请求">7.3 处理PUT和DELETE请求</h3>
<p>浏览器目前只能发送get和post请求</p>
<p>若要发送put和delete请求，需要在web.xml中配置一个过滤器HiddenHttpMethodFilter，配置了过滤器之后，发送的请求要满足两个条件，才能将请求方式转换为put和delete</p>
<p>1、当前请求的请求方式必须为post</p>
<p>2、当前请求必须传输请求参数_method，_method的值才是最终的请求方式</p>
<h4 id="源码分析">源码分析</h4>
<p>HiddenHttpMethodFilter：</p>
<p>请求方式必须是post，获取参数_method的值</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@Override</span></span><br><span class="line"><span class="keyword">protected</span> <span class="keyword">void</span> <span class="title function_">doFilterInternal</span><span class="params">(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)</span></span><br><span class="line">      <span class="keyword">throws</span> ServletException, IOException &#123;</span><br><span class="line"></span><br><span class="line">   <span class="type">HttpServletRequest</span> <span class="variable">requestToUse</span> <span class="operator">=</span> request;</span><br><span class="line"></span><br><span class="line">    <span class="comment">//如果当前请求是post且没有异常就进入</span></span><br><span class="line">   <span class="keyword">if</span> (<span class="string">&quot;POST&quot;</span>.equals(request.getMethod()) &amp;&amp; request.getAttribute(WebUtils.ERROR_EXCEPTION_ATTRIBUTE) == <span class="literal">null</span>) &#123;</span><br><span class="line">       <span class="comment">//得到_method参数的值，然后再根据值指定的方法创建一个对应方法的request</span></span><br><span class="line">      <span class="type">String</span> <span class="variable">paramValue</span> <span class="operator">=</span> request.getParameter(<span class="built_in">this</span>.methodParam);</span><br><span class="line">       <span class="comment">//判断是否有值</span></span><br><span class="line">      <span class="keyword">if</span> (StringUtils.hasLength(paramValue)) &#123;</span><br><span class="line">         <span class="type">String</span> <span class="variable">method</span> <span class="operator">=</span> paramValue.toUpperCase(Locale.ENGLISH);</span><br><span class="line">         <span class="keyword">if</span> (ALLOWED_METHODS.contains(method)) &#123;</span><br><span class="line">            requestToUse = <span class="keyword">new</span> <span class="title class_">HttpMethodRequestWrapper</span>(request, method);</span><br><span class="line">         &#125;</span><br><span class="line">      &#125;</span><br><span class="line">   &#125;</span><br><span class="line"></span><br><span class="line">   filterChain.doFilter(requestToUse, response);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment">//这个内部类，传入request和method，重写了getMethod方法，之后获取method都是PUT或者DELETE</span></span><br><span class="line"><span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">class</span> <span class="title class_">HttpMethodRequestWrapper</span> <span class="keyword">extends</span> <span class="title class_">HttpServletRequestWrapper</span> &#123;</span><br><span class="line"></span><br><span class="line">   <span class="keyword">private</span> <span class="keyword">final</span> String method;</span><br><span class="line"></span><br><span class="line">   <span class="keyword">public</span> <span class="title function_">HttpMethodRequestWrapper</span><span class="params">(HttpServletRequest request, String method)</span> &#123;</span><br><span class="line">      <span class="built_in">super</span>(request);</span><br><span class="line">      <span class="built_in">this</span>.method = method;</span><br><span class="line">   &#125;</span><br><span class="line"></span><br><span class="line">   <span class="meta">@Override</span></span><br><span class="line">   <span class="keyword">public</span> String <span class="title function_">getMethod</span><span class="params">()</span> &#123;</span><br><span class="line">      <span class="keyword">return</span> <span class="built_in">this</span>.method;</span><br><span class="line">   &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<h2 id="8-RESTful案例😑">8 RESTful案例😑</h2>
<p>这一部分就是实现一个增删改查，使用RESTful风格实现</p>
<h3 id="8-1-功能">8.1 功能</h3>
<ul>
<li>查询所有的员工信息 --&gt;/employee–&gt;get</li>
<li>跳转到添加页面 --&gt;/to/add–&gt;get</li>
<li>新增员工信息 --&gt;/employee–&gt;post</li>
<li>跳转到修改页面 --&gt;/employee/1–&gt;get</li>
<li>修改员工信息 --&gt;/employee–&gt;put</li>
<li>删除员工信息 --&gt;/employee/1–&gt;delete</li>
</ul>
<h3 id="8-2-处理静态资源">8.2 处理静态资源</h3>
<h4 id="由css文件引入">由css文件引入</h4>
<p>在员工列表的页面引入css文件</p>
<figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">link</span> <span class="attr">rel</span>=<span class="string">&quot;stylesheet&quot;</span> <span class="attr">th:href</span>=<span class="string">&quot;@&#123;/static/css/index_work.css&#125;&quot;</span>&gt;</span></span><br></pre></td></tr></table></figure>
<p>DispatcherServlet会拦截除了jsp之外的所有请求，当请求静态资源时，该请求也会被DispatcherServlet处理，然而他处理不了，需要交给Tomcat处理。</p>
<h4 id="DispatcherServlet和Tomcat的DefaultServlet">DispatcherServlet和Tomcat的DefaultServlet</h4>
<p>当前工程的web.xml配置的前端控制器DispatcherServlet的url-pattern是<code>/</code></p>
<p>而Tomcat的web.xml配置的默认的控制器DefaultServlet的url-pattern也是<code>/</code></p>
<p>此时，浏览器发送的请求优先会被DispatcherServlet进行处理，但是DispatcherServlet无法处理静态资源。因此需要把静态资源的处理交给默认的servlet，进行如下配置：</p>
<p>若配置了<code>&lt;mvc:default-servlet-handler/&gt;</code>，此时浏览器发送的所有请求都会被DefaultServlet处理，DispatcherServlet无法进行处理</p>
<p>因此还需要开启mvc的注解驱动<code>&lt;mvc:annotation-driven /&gt;</code>,这样浏览器发送的请求会先被DispatcherServlet处理，无法处理再交给DefaultServlet处理</p>
<p>如果Tomcat中的web.xml的配置和工程中的web.xml配置冲突，会以当前工程的配置为准。</p>
<h3 id="8-3-功能实现">8.3 功能实现</h3>
<blockquote>
<p>这一部分没啥的，正常的crud</p>
</blockquote>
<p>控制器：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@Controller</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">EmployeeController</span> &#123;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Autowired</span></span><br><span class="line">    <span class="keyword">private</span> EmployeeDao employeeDao;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@GetMapping(&quot;/employee&quot;)</span></span><br><span class="line">    <span class="keyword">public</span> String <span class="title function_">getAllEmployee</span><span class="params">(Model model)</span>&#123;</span><br><span class="line">        <span class="comment">//获取所有的员工信息</span></span><br><span class="line">        Collection&lt;Employee&gt; employeeList = employeeDao.getAll();</span><br><span class="line">        <span class="comment">//将所有的员工信息在请求域中共享</span></span><br><span class="line">        model.addAttribute(<span class="string">&quot;employeeList&quot;</span>,employeeList);</span><br><span class="line">        <span class="comment">//跳转到列表页面</span></span><br><span class="line">        <span class="keyword">return</span> <span class="string">&quot;employee_list&quot;</span>;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@PostMapping(&quot;/employee&quot;)</span></span><br><span class="line">    <span class="keyword">public</span> String <span class="title function_">addEmployee</span><span class="params">(Employee employee)</span>&#123;</span><br><span class="line">        <span class="comment">//保存员工信息</span></span><br><span class="line">        employeeDao.save(employee);</span><br><span class="line">        <span class="comment">//访问列表功能，调用查询数据</span></span><br><span class="line">        <span class="comment">//重定向</span></span><br><span class="line">        <span class="keyword">return</span> <span class="string">&quot;redirect:/employee&quot;</span>;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@GetMapping(&quot;/employee/&#123;id&#125;&quot;)</span></span><br><span class="line">    <span class="keyword">public</span> String <span class="title function_">toUpdate</span><span class="params">(<span class="meta">@PathVariable(&quot;id&quot;)</span> Integer id,Model model)</span>&#123;</span><br><span class="line">        <span class="comment">//根据id查询信息</span></span><br><span class="line">        <span class="type">Employee</span> <span class="variable">employee</span> <span class="operator">=</span> employeeDao.get(id);</span><br><span class="line">        <span class="comment">//将员工信息共享到请求域中</span></span><br><span class="line">        model.addAttribute(<span class="string">&quot;employee&quot;</span>,employee);</span><br><span class="line">        <span class="comment">//跳转</span></span><br><span class="line">        <span class="keyword">return</span> <span class="string">&quot;employee_update&quot;</span>;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@PutMapping(&quot;/employee&quot;)</span></span><br><span class="line">    <span class="keyword">public</span> String <span class="title function_">updateEmployee</span><span class="params">(Employee employee)</span>&#123;</span><br><span class="line">        <span class="comment">//更新信息</span></span><br><span class="line">        employeeDao.save(employee);</span><br><span class="line">        <span class="comment">//重定向</span></span><br><span class="line">        <span class="keyword">return</span> <span class="string">&quot;redirect:/employee&quot;</span>;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@DeleteMapping(&quot;/employee/&#123;id&#125;&quot;)</span></span><br><span class="line">    <span class="keyword">public</span> String <span class="title function_">deleteEmployeeById</span><span class="params">(<span class="meta">@PathVariable(&quot;id&quot;)</span> Integer id)</span>&#123;</span><br><span class="line">        employeeDao.delete(id);</span><br><span class="line">        <span class="keyword">return</span> <span class="string">&quot;redirect:/employee&quot;</span>;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>前端页面，就以员工列表页为例</p>
<figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">&lt;!DOCTYPE <span class="keyword">html</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">html</span> <span class="attr">lang</span>=<span class="string">&quot;en&quot;</span> <span class="attr">xmlns:th</span>=<span class="string">&quot;http://www.thymeleaf.org&quot;</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">head</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">meta</span> <span class="attr">charset</span>=<span class="string">&quot;UTF-8&quot;</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">title</span>&gt;</span>employee list<span class="tag">&lt;/<span class="name">title</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">link</span> <span class="attr">rel</span>=<span class="string">&quot;stylesheet&quot;</span> <span class="attr">th:href</span>=<span class="string">&quot;@&#123;/static/css/index_work.css&#125;&quot;</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">head</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">body</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">div</span> <span class="attr">id</span>=<span class="string">&quot;app&quot;</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">table</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">tr</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">th</span> <span class="attr">colspan</span>=<span class="string">&quot;5&quot;</span>&gt;</span>employee list<span class="tag">&lt;/<span class="name">th</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;/<span class="name">tr</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">tr</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">th</span>&gt;</span>id<span class="tag">&lt;/<span class="name">th</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">th</span>&gt;</span>lastName<span class="tag">&lt;/<span class="name">th</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">th</span>&gt;</span>email<span class="tag">&lt;/<span class="name">th</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">th</span>&gt;</span>gender<span class="tag">&lt;/<span class="name">th</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">th</span>&gt;</span>options(<span class="tag">&lt;<span class="name">a</span> <span class="attr">th:href</span>=<span class="string">&quot;@&#123;/to/add&#125;&quot;</span>&gt;</span>add<span class="tag">&lt;/<span class="name">a</span>&gt;</span> )<span class="tag">&lt;/<span class="name">th</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;/<span class="name">tr</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">tr</span> <span class="attr">th:each</span>=<span class="string">&quot;employee : $&#123;employeeList&#125;&quot;</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">td</span> <span class="attr">th:text</span>=<span class="string">&quot;$&#123;employee.id&#125;&quot;</span>&gt;</span><span class="tag">&lt;/<span class="name">td</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">td</span> <span class="attr">th:text</span>=<span class="string">&quot;$&#123;employee.lastName&#125;&quot;</span>&gt;</span><span class="tag">&lt;/<span class="name">td</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">td</span> <span class="attr">th:text</span>=<span class="string">&quot;$&#123;employee.email&#125;&quot;</span>&gt;</span><span class="tag">&lt;/<span class="name">td</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">td</span> <span class="attr">th:text</span>=<span class="string">&quot;$&#123;employee.gender&#125;&quot;</span>&gt;</span><span class="tag">&lt;/<span class="name">td</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">td</span>&gt;</span></span><br><span class="line">                <span class="tag">&lt;<span class="name">a</span> @<span class="attr">click</span>=<span class="string">&quot;deleteEmployee()&quot;</span> <span class="attr">th:href</span>=<span class="string">&quot;@&#123;|/employee/$&#123;employee.id&#125;|&#125;&quot;</span>&gt;</span>delete<span class="tag">&lt;/<span class="name">a</span>&gt;</span></span><br><span class="line">                <span class="tag">&lt;<span class="name">a</span> <span class="attr">th:href</span>=<span class="string">&quot;@&#123;|/employee/$&#123;employee.id&#125;|&#125;&quot;</span>&gt;</span>update<span class="tag">&lt;/<span class="name">a</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;/<span class="name">td</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;/<span class="name">tr</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">table</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">form</span> <span class="attr">method</span>=<span class="string">&quot;post&quot;</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">input</span> <span class="attr">type</span>=<span class="string">&quot;hidden&quot;</span> <span class="attr">name</span>=<span class="string">&quot;_method&quot;</span> <span class="attr">value</span>=<span class="string">&quot;delete&quot;</span>/&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">form</span>&gt;</span></span><br><span class="line"></span><br><span class="line"><span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">script</span> <span class="attr">type</span>=<span class="string">&quot;text/javascript&quot;</span> <span class="attr">src</span>=<span class="string">&quot;https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js&quot;</span>&gt;</span><span class="tag">&lt;/<span class="name">script</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">script</span> <span class="attr">type</span>=<span class="string">&quot;text/javascript&quot;</span>&gt;</span><span class="language-javascript"></span></span><br><span class="line"><span class="language-javascript">    <span class="keyword">var</span> vue = <span class="keyword">new</span> <span class="title class_">Vue</span>(&#123;</span></span><br><span class="line"><span class="language-javascript">        <span class="attr">el</span>:<span class="string">&quot;#app&quot;</span>,</span></span><br><span class="line"><span class="language-javascript">        <span class="attr">methods</span>:&#123;</span></span><br><span class="line"><span class="language-javascript">            <span class="title function_">deleteEmployee</span>(<span class="params"></span>)&#123;</span></span><br><span class="line"><span class="language-javascript">                <span class="comment">//获取表单</span></span></span><br><span class="line"><span class="language-javascript">                <span class="keyword">var</span> form = <span class="variable language_">document</span>.<span class="title function_">getElementsByTagName</span>(<span class="string">&quot;form&quot;</span>)[<span class="number">0</span>]</span></span><br><span class="line"><span class="language-javascript">                <span class="comment">//将超链接的href属性赋值给form表单的action属性</span></span></span><br><span class="line"><span class="language-javascript">                form.<span class="property">acton</span> = event.<span class="property">target</span>.<span class="property">href</span>;</span></span><br><span class="line"><span class="language-javascript">                <span class="comment">//表单提交</span></span></span><br><span class="line"><span class="language-javascript">                form.<span class="title function_">submit</span>();</span></span><br><span class="line"><span class="language-javascript">                <span class="comment">//阻止超链接的默认行为</span></span></span><br><span class="line"><span class="language-javascript">                event.<span class="title function_">preventDefault</span>();</span></span><br><span class="line"><span class="language-javascript">            &#125;</span></span><br><span class="line"><span class="language-javascript">        &#125;</span></span><br><span class="line"><span class="language-javascript">    &#125;)</span></span><br><span class="line"><span class="language-javascript"></span><span class="tag">&lt;/<span class="name">script</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">body</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">html</span>&gt;</span></span><br></pre></td></tr></table></figure>
<h2 id="9-SpringMVC处理ajax请求🌟">9 SpringMVC处理ajax请求🌟</h2>
<blockquote>
<p>更详细的介绍见https://heavy_code_industry.gitee.io/code_heavy_industry/pro001-javaweb/lecture/chapter12/</p>
</blockquote>
<h3 id="9-1-ajax介绍🤣">9.1 ajax介绍🤣</h3>
<h4 id="服务端渲染与ajax渲染">服务端渲染与ajax渲染</h4>
<p>服务端渲染</p>
<p><img src="https://zylai-cloud-pic-1306915061.cos.ap-nanjing.myqcloud.com/images01/SpringMVC.assets/image-20220730212558630.png" alt="image-20220730212558630"></p>
<p>ajax渲染（局部更新）</p>
<p><img src="https://zylai-cloud-pic-1306915061.cos.ap-nanjing.myqcloud.com/images01/SpringMVC.assets/image-20220730212626998.png" alt="image-20220730212626998"></p>
<h4 id="前后端分离">前后端分离</h4>
<p>彻底舍弃服务器端渲染，数据全部通过Ajax方式以JSON格式来传递。</p>
<h4 id="异步和同步">异步和同步</h4>
<p>Ajax本身就是Asynchronous JavaScript And XML的缩写，直译为：异步的JavaScript和XML。在实际应用中Ajax指的是：<strong>不刷新浏览器窗口</strong>，<strong>不做页面跳转</strong>，<strong>局部更新页面内容</strong>的技术。</p>
<p><img src="https://zylai-cloud-pic-1306915061.cos.ap-nanjing.myqcloud.com/images01/SpringMVC.assets/image-20220730213049049.png" alt="image-20220730213049049"></p>
<p><img src="https://zylai-cloud-pic-1306915061.cos.ap-nanjing.myqcloud.com/images01/SpringMVC.assets/image-20220730213101052.png" alt="image-20220730213101052"></p>
<h4 id="axios">axios</h4>
<p>发送请求的方式之一：（一般不使用这个，这里用这个详细介绍一下axios）</p>
<p>参数用params方式，参数拼接到地址栏中。参数用data方式，参数放在请求体中。</p>
<figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="title function_">axios</span>(&#123;</span><br><span class="line">               <span class="attr">url</span>:<span class="string">&quot;&quot;</span>,<span class="comment">//请求路径</span></span><br><span class="line">               <span class="attr">method</span>:<span class="string">&quot;&quot;</span>,<span class="comment">//请求方式</span></span><br><span class="line">               <span class="comment">//请求参数，以name=value&amp;name=value的方式，</span></span><br><span class="line">               <span class="comment">//不管使用的请求方式是get或者post，请求参数都会被拼接到请求地址后</span></span><br><span class="line">               <span class="comment">// 此种方式可以通过request.getParameter()获取</span></span><br><span class="line">               <span class="attr">params</span>:&#123;&#125;,</span><br><span class="line">               <span class="comment">//请求参数，以json格式发送，</span></span><br><span class="line">               <span class="comment">// 请求参数会被保存到请求报文的请求体传输到服务器，因此不能使用get，get没有请求体</span></span><br><span class="line">               <span class="comment">// 需要获取请求体，之后把请求体中的json数据进行处理，会使用一些处理json的jar包处理</span></span><br><span class="line">               <span class="attr">data</span>:&#123;&#125;</span><br><span class="line">           &#125;).<span class="title function_">then</span>(<span class="function"><span class="params">res</span>=&gt;</span>&#123;</span><br><span class="line">               <span class="variable language_">console</span>.<span class="title function_">log</span>(res.<span class="property">data</span>)</span><br><span class="line">           &#125;)</span><br></pre></td></tr></table></figure>
<p>发送请求的方式二：</p>
<figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line">axios.<span class="title function_">post</span>(</span><br><span class="line">    <span class="comment">//url，要加上上下文路径</span></span><br><span class="line">    <span class="string">&quot;/SpringMVC/test/ajax?id=1001&quot;</span>,</span><br><span class="line">    <span class="comment">//json类型的数据，会被封装在请求体中</span></span><br><span class="line">    &#123;<span class="attr">username</span>:<span class="string">&quot;admin&quot;</span>,<span class="attr">password</span>:<span class="string">&quot;123456&quot;</span>&#125;</span><br><span class="line">).<span class="title function_">then</span>(<span class="function"><span class="params">res</span>=&gt;</span>&#123;<span class="comment">//请求成功的响应</span></span><br><span class="line">    <span class="comment">//服务器返回的结果封装到data属性中</span></span><br><span class="line">    <span class="variable language_">console</span>.<span class="title function_">log</span>(res.<span class="property">data</span>)</span><br><span class="line">&#125;)</span><br></pre></td></tr></table></figure>
<h3 id="9-2-RequestBody注解">9.2 @RequestBody注解</h3>
<p>该注解将请求体中的内容和形参进行绑定。由于axios发送请求把请求参数放到了请求体中，所以需要这个注解来获取请求体中的内容。</p>
<figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="title function_">testAjax</span>(<span class="params"></span>)&#123;</span><br><span class="line">    axios.<span class="title function_">post</span>(</span><br><span class="line">        <span class="comment">//url，要加上上下文路径</span></span><br><span class="line">        <span class="string">&quot;/SpringMVC/test/ajax?id=1001&quot;</span>,</span><br><span class="line">        <span class="comment">//json类型的数据，会被封装在请求体中</span></span><br><span class="line">        &#123;<span class="attr">username</span>:<span class="string">&quot;admin&quot;</span>,<span class="attr">password</span>:<span class="string">&quot;123456&quot;</span>&#125;</span><br><span class="line">    ).<span class="title function_">then</span>(<span class="function"><span class="params">res</span>=&gt;</span>&#123;<span class="comment">//请求成功的响应</span></span><br><span class="line">        <span class="comment">//服务器返回的结果封装到data属性中</span></span><br><span class="line">        <span class="variable language_">console</span>.<span class="title function_">log</span>(res.<span class="property">data</span>)</span><br><span class="line">    &#125;)</span><br><span class="line">&#125;,</span><br></pre></td></tr></table></figure>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@RequestMapping(&quot;/test/ajax&quot;)</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">testAjax</span><span class="params">(Integer id, <span class="meta">@RequestBody</span> String requestBody, HttpServletResponse response)</span> <span class="keyword">throws</span> IOException &#123;</span><br><span class="line">    System.out.println(<span class="string">&quot;id:&quot;</span>+id);</span><br><span class="line">    System.out.println(<span class="string">&quot;requestBody:&quot;</span>+requestBody);</span><br><span class="line">    response.getWriter().write(<span class="string">&quot;hello.axios&quot;</span>);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>控制台打印：</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">id:1001</span><br><span class="line">requestBody:&#123;&quot;username&quot;:&quot;admin&quot;,&quot;password&quot;:&quot;123456&quot;&#125;</span><br></pre></td></tr></table></figure>
<h3 id="9-3-RequestBody注解将json格式的数据转为java对象🍰">9.3 @RequestBody注解将json格式的数据转为java对象🍰</h3>
<p>由于axios的请求体中是json格式，我们需要进行转换</p>
<p>步骤：</p>
<h4 id="1、导入jackson的依赖">1、导入jackson的依赖</h4>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>com.fasterxml.jackson.core<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>jackson-databind<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">version</span>&gt;</span>2.12.1<span class="tag">&lt;/<span class="name">version</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br></pre></td></tr></table></figure>
<h4 id="2、在SpringMVC配置文件中设置开启mvc的注解驱动">2、在SpringMVC配置文件中设置开启mvc的注解驱动</h4>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">mvc:annotation-driven</span> /&gt;</span></span><br></pre></td></tr></table></figure>
<h4 id="3、在控制器方法的形参前设置-RequestBody注解">3、在控制器方法的形参前设置@RequestBody注解</h4>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@RequestMapping(&quot;/test/requestbody/json&quot;)</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">testRequestBody</span><span class="params">(<span class="meta">@RequestBody</span> User user, HttpServletResponse response)</span> <span class="keyword">throws</span> IOException &#123;</span><br><span class="line">    System.out.println(user);</span><br><span class="line">    response.getWriter().write(<span class="string">&quot;hello,requestBody&quot;</span>);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<h3 id="9-4-ResponseBody注解">9.4 @ResponseBody注解</h3>
<p>就是把所标识的方法的返回值作为响应报文的响应体响应到浏览器。</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@RequestMapping(&quot;/test/responsebody&quot;)</span></span><br><span class="line"><span class="comment">//这个注解就是把方法的返回值作为请求的返回体返回给浏览器</span></span><br><span class="line"><span class="meta">@ResponseBody</span></span><br><span class="line"><span class="keyword">public</span> String <span class="title function_">testResponseBody</span><span class="params">()</span>&#123;</span><br><span class="line">    <span class="keyword">return</span> <span class="string">&quot;success&quot;</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>这里直接将内容显示到浏览器中</p>
<p><img src="https://zylai-cloud-pic-1306915061.cos.ap-nanjing.myqcloud.com/images01/SpringMVC.assets/image-20220730215003861.png" alt="image-20220730215003861"></p>
<h3 id="9-5-ResponseBody注解响应给浏览器json格式数据">9.5 @ResponseBody注解响应给浏览器json格式数据</h3>
<h4 id="java-json">java --&gt; json</h4>
<p>如何将java对象响应过去？如果直接如果直接response.getWriter().write，加入java对象，是返回的内存地址或者返回了一个toString方法的返回值，再者，如果将java类型的对象返回了，那么浏览器也不能处理java类型的数据。</p>
<p>一般都是奖java转换为json值返回</p>
<h4 id="步骤：（和上面的差不多）">步骤：（和上面的差不多）</h4>
<ol>
<li>导入jackson的依赖</li>
<li>在SpringMVC配置文件中设置开启mvc的注解驱动</li>
<li>将需要转换为json字符串的Java对象作为控制器方法的返回值，使用@ResponseBody注解标识控制器方法就可以将java对象直接转化为json字符串，并响应到浏览器</li>
</ol>
<p>非常方便，省略了将返回的java对象转换为json的过程，由框架完成</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//非常方便，省略了将返回的java对象转换为json的过程，由框架完成</span></span><br><span class="line"><span class="meta">@RequestMapping(&quot;/test/responsebody/json&quot;)</span></span><br><span class="line"><span class="meta">@ResponseBody</span></span><br><span class="line"><span class="keyword">public</span> User <span class="title function_">testResponseBodyJson</span><span class="params">()</span>&#123;</span><br><span class="line">    <span class="type">User</span> <span class="variable">user</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">User</span>(<span class="number">1001</span>,<span class="string">&quot;admin&quot;</span>,<span class="string">&quot;23232&quot;</span>,<span class="number">20</span>,<span class="string">&quot;男&quot;</span>);</span><br><span class="line">    <span class="keyword">return</span> user;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p><img src="https://zylai-cloud-pic-1306915061.cos.ap-nanjing.myqcloud.com/images01/SpringMVC.assets/image-20220730215806682.png" alt="image-20220730215806682"></p>
<h4 id="转换关系">转换关系</h4>
<p>常用的java对象转化为json的结果：</p>
<ul>
<li>实体类–&gt;json对象</li>
<li>map–&gt;json对象</li>
<li>List–&gt;json数组</li>
</ul>
<p><img src="https://zylai-cloud-pic-1306915061.cos.ap-nanjing.myqcloud.com/images01/SpringMVC.assets/image-20220730184555834.png" alt="image-20220730184555834"></p>
<h3 id="9-6-RestController注解">9.6 @RestController注解</h3>
<p>@RestController注解是springMVC提供的一个复合注解，标识在控制器的类上，就相当于为类添加了<br>
@Controller注解，并且为其中的每个方法添加了@ResponseBody注解</p>
<h2 id="10-文件上传和下载">10 文件上传和下载</h2>
<h3 id="10-1-文件下载">10.1 文件下载</h3>
<p>ResponseEntity:可以作为控制器方法的返回值，表示响应到浏览器的完整的响应报文</p>
<blockquote>
<p>如果不设置返回，返回值为void，那么会默认将请求地址作为逻辑视图</p>
<p>下面这个，一般当成一个模板用就可以了</p>
</blockquote>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br></pre></td><td class="code"><pre><span class="line">    <span class="meta">@RequestMapping(&quot;/test/down&quot;)</span></span><br><span class="line">    <span class="keyword">public</span> ResponseEntity&lt;<span class="type">byte</span>[]&gt; testResponseEntity(HttpSession session) <span class="keyword">throws</span></span><br><span class="line">            IOException &#123;</span><br><span class="line"><span class="comment">//获取ServletContext对象</span></span><br><span class="line">        <span class="type">ServletContext</span> <span class="variable">servletContext</span> <span class="operator">=</span> session.getServletContext();</span><br><span class="line"><span class="comment">//获取服务器中文件的真实路径，其实就是直接把这个路径拼接到项目的后面</span></span><br><span class="line">        <span class="type">String</span> <span class="variable">realPath</span> <span class="operator">=</span> servletContext.getRealPath(<span class="string">&quot;img&quot;</span>);</span><br><span class="line">        <span class="comment">//E:\code_workspace\study_SSM\spring_mvc04_ajax\target\spring_mvc04_ajax-1.0-SNAPSHOT\</span></span><br><span class="line">        realPath = realPath + File.separator+<span class="string">&quot;avatar.jpg&quot;</span>;</span><br><span class="line"><span class="comment">//创建输入流</span></span><br><span class="line">        <span class="type">InputStream</span> <span class="variable">is</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">FileInputStream</span>(realPath);</span><br><span class="line"><span class="comment">//创建字节数组，is.available()获取输入流所对应的文件的字节数。</span></span><br><span class="line"><span class="comment">//        对于流，可以设置响应的读取策略，可以适量多次读取</span></span><br><span class="line">        <span class="type">byte</span>[] bytes = <span class="keyword">new</span> <span class="title class_">byte</span>[is.available()];</span><br><span class="line"><span class="comment">//将流读到字节数组中</span></span><br><span class="line">        is.read(bytes);</span><br><span class="line"><span class="comment">//创建HttpHeaders对象设置响应头信息</span></span><br><span class="line">        MultiValueMap&lt;String, String&gt; headers = <span class="keyword">new</span> <span class="title class_">HttpHeaders</span>();</span><br><span class="line"><span class="comment">//设置要下载方式以及下载文件的名字，attachment：以附件的方式下载</span></span><br><span class="line">        headers.add(<span class="string">&quot;Content-Disposition&quot;</span>, <span class="string">&quot;attachment;filename=avatar.jpg&quot;</span>);</span><br><span class="line"><span class="comment">//设置响应状态码</span></span><br><span class="line">        <span class="type">HttpStatus</span> <span class="variable">statusCode</span> <span class="operator">=</span> HttpStatus.OK;</span><br><span class="line"><span class="comment">//创建ResponseEntity对象</span></span><br><span class="line">        ResponseEntity&lt;<span class="type">byte</span>[]&gt; responseEntity = <span class="keyword">new</span> <span class="title class_">ResponseEntity</span>&lt;&gt;(bytes, headers,</span><br><span class="line">                statusCode);</span><br><span class="line"><span class="comment">//关闭输入流</span></span><br><span class="line">        is.close();</span><br><span class="line">        <span class="keyword">return</span> responseEntity;</span><br><span class="line">    &#125;</span><br></pre></td></tr></table></figure>
<h3 id="10-2-文件上传">10.2 文件上传</h3>
<p>要求：</p>
<ol>
<li>form表单的请求方式必须是post</li>
<li>form表单必须设置属性enctype=“multipart/form-data”，保证以二进制方式上传</li>
</ol>
<p>步骤：</p>
<ol>
<li>
<p>添加依赖</p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">&lt;!-- https://mvnrepository.com/artifact/commons-fileupload/commons-fileupload --&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>commons-fileupload<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>commons-fileupload<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">version</span>&gt;</span>1.3.1<span class="tag">&lt;/<span class="name">version</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br></pre></td></tr></table></figure>
</li>
<li>
<p>配置bean</p>
<p>注意设置id，id名固定</p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">&lt;!--必须通过文件解析器的解析才能将文件转换为MultipartFile对象</span></span><br><span class="line"><span class="comment">    这里的id必须是multipartResolver，因为这里是根据id获取bean的--&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">bean</span> <span class="attr">id</span>=<span class="string">&quot;multipartResolver&quot;</span> <span class="attr">class</span>=<span class="string">&quot;org.springframework.web.multipart.commons.CommonsMultipartResolver&quot;</span>&gt;</span></span><br><span class="line">    <span class="comment">&lt;!--&lt;property name=&quot;defaultEncoding&quot; value=&quot;UTF-8&quot;/&gt;--&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">bean</span>&gt;</span></span><br></pre></td></tr></table></figure>
</li>
<li>
<p>控制器方法</p>
<p>注意点：使用MultipartFile类型参数接收，注意把他当成一个普通参数就可，需要匹配请求的参数</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@RequestMapping(&quot;/test/up&quot;)</span></span><br><span class="line"><span class="comment">//注意：这里的MultipartFile不是由框架自动填充（就像request和session那样赋值），</span></span><br><span class="line"><span class="comment">// 而是像普通参数一样从请求参数中获取</span></span><br><span class="line"><span class="keyword">public</span> String <span class="title function_">testUp</span><span class="params">(<span class="meta">@RequestParam(&quot;photo&quot;)</span> MultipartFile photo, HttpSession session)</span> <span class="keyword">throws</span> IOException &#123;</span><br><span class="line">    <span class="comment">//获取上传的文件的文件名</span></span><br><span class="line">    <span class="type">String</span> <span class="variable">filename</span> <span class="operator">=</span> photo.getOriginalFilename();</span><br><span class="line">    <span class="comment">//处理文件重名问题</span></span><br><span class="line">    <span class="comment">//获取上传的文件的后缀名</span></span><br><span class="line">    <span class="type">String</span> <span class="variable">fileType</span> <span class="operator">=</span> filename.substring(filename.lastIndexOf(<span class="string">&quot;.&quot;</span>));</span><br><span class="line">    filename = UUID.randomUUID().toString() + fileType;</span><br><span class="line">    System.out.println(filename);</span><br><span class="line">    <span class="comment">//获取ServletContext对象</span></span><br><span class="line">    <span class="type">ServletContext</span> <span class="variable">servletContext</span> <span class="operator">=</span> session.getServletContext();</span><br><span class="line"></span><br><span class="line">    <span class="comment">//获取当前工程下photo目录的真实路径</span></span><br><span class="line">    <span class="type">String</span> <span class="variable">photoPath</span> <span class="operator">=</span> servletContext.getRealPath(<span class="string">&quot;photo&quot;</span>);</span><br><span class="line"></span><br><span class="line">    <span class="comment">//创建photoPath所对应的File对象</span></span><br><span class="line">    <span class="type">File</span> <span class="variable">file</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">File</span>(photoPath);</span><br><span class="line">    <span class="comment">//判断file对应的目录是否存在</span></span><br><span class="line">    <span class="keyword">if</span>(!file.exists())&#123;</span><br><span class="line">        file.mkdir();</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="type">String</span> <span class="variable">finalPath</span> <span class="operator">=</span> photoPath + File.separator + filename;</span><br><span class="line">    <span class="comment">//文件上传</span></span><br><span class="line">    photo.transferTo(<span class="keyword">new</span> <span class="title class_">File</span>(finalPath));</span><br><span class="line">    <span class="keyword">return</span> <span class="string">&quot;success&quot;</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
</li>
</ol>
<h3 id="10-3-文件上传的重命名问题">10.3 文件上传的重命名问题</h3>
<p>使用UUID命名，UUID加上文件后缀名即可。</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//处理文件重名问题</span></span><br><span class="line"><span class="comment">//获取上传的文件的后缀名</span></span><br><span class="line"><span class="type">String</span> <span class="variable">fileType</span> <span class="operator">=</span> filename.substring(filename.lastIndexOf(<span class="string">&quot;.&quot;</span>));</span><br><span class="line">filename = UUID.randomUUID().toString() + fileType;</span><br><span class="line">System.out.println(filename);</span><br></pre></td></tr></table></figure>
<blockquote>
<p>下面这些知识点用的不多，了解即可</p>
</blockquote>
<h2 id="11-拦截器">11 拦截器</h2>
<p>请求经过过滤器，过滤器放行之后DispatcherServlet处理请求，而拦截器用于拦截控制器方法的执行</p>
<h3 id="11-1-拦截器的配置">11.1 拦截器的配置</h3>
<p>SpringMVC中的拦截器用于拦截控制器方法的执行</p>
<p>SpringMVC中的拦截器需要实现HandlerInterceptor接口</p>
<p>SpringMVC的拦截器必须在SpringMVC的配置文件中进行配置：</p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">mvc:interceptor</span>&gt;</span></span><br><span class="line">	<span class="tag">&lt;<span class="name">bean</span> <span class="attr">class</span>=<span class="string">&quot;com.atguigu.interceptor.FirstInterceptor&quot;</span>&gt;</span>	<span class="tag">&lt;/<span class="name">bean</span>&gt;</span></span><br><span class="line">	<span class="tag">&lt;<span class="name">ref</span> <span class="attr">bean</span>=<span class="string">&quot;firstInterceptor&quot;</span>&gt;</span><span class="tag">&lt;/<span class="name">ref</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">mvc:interceptor</span>&gt;</span></span><br><span class="line"></span><br><span class="line"><span class="comment">&lt;!-- 以上两种配置方式都是对DispatcherServlet所处理的所有的请求进行拦截 --&gt;</span></span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="tag">&lt;<span class="name">mvc:interceptor</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">mvc:mapping</span> <span class="attr">path</span>=<span class="string">&quot;/**&quot;</span>/&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">mvc:exclude-mapping</span> <span class="attr">path</span>=<span class="string">&quot;/testRequestEntity&quot;</span>/&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">ref</span> <span class="attr">bean</span>=<span class="string">&quot;firstInterceptor&quot;</span>&gt;</span><span class="tag">&lt;/<span class="name">ref</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">mvc:interceptor</span>&gt;</span></span><br><span class="line"><span class="comment">&lt;!-- </span></span><br><span class="line"><span class="comment">	以上配置方式可以通过ref或bean标签设置拦截器，通过mvc:mapping设置需要拦截的请求（/**匹配所有的请求)，通过mvc:exclude-mapping设置需要排除的请求，即不需要拦截的请求</span></span><br><span class="line"><span class="comment">--&gt;</span></span><br></pre></td></tr></table></figure>
<p>总结：bean和ref的配置方式都是对所有请求进行拦截，而mvc:mapping可以设置拦截的请求</p>
<h3 id="11-2-拦截器的三个抽象方法">11.2 拦截器的三个抽象方法</h3>
<p>SpringMVC中的拦截器有三个抽象方法：</p>
<p>preHandle：控制器方法执行之前执行preHandle()，其boolean类型的返回值表示是否拦截或放行，返回true为放行，即调用控制器方法；返回false表示拦截，即不调用控制器方法</p>
<p>postHandle：控制器方法执行之后执行postHandle()</p>
<p>afterComplation：处理完视图和模型数据，渲染视图完毕之后执行afterComplation()</p>
<p>拦截器的类要实现HandlerInterceptor接口，并重写其中的三个默认的抽象方法（使用Ctrl+O快捷键）</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">FirstInterceptor</span> <span class="keyword">implements</span> <span class="title class_">HandlerInterceptor</span> &#123;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="keyword">public</span> <span class="type">boolean</span> <span class="title function_">preHandle</span><span class="params">(HttpServletRequest request, HttpServletResponse response, Object handler)</span> <span class="keyword">throws</span> Exception &#123;</span><br><span class="line">        System.out.println(<span class="string">&quot;FirstInterceptor --&gt; preHandle&quot;</span>);</span><br><span class="line">        <span class="keyword">return</span> <span class="literal">true</span>;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">postHandle</span><span class="params">(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView)</span> <span class="keyword">throws</span> Exception &#123;</span><br><span class="line">        System.out.println(<span class="string">&quot;FirstInterceptor --&gt; postHandle&quot;</span>);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">afterCompletion</span><span class="params">(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)</span> <span class="keyword">throws</span> Exception &#123;</span><br><span class="line">        System.out.println(<span class="string">&quot;FirstInterceptor --&gt; afterCompletion&quot;</span>);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<h3 id="11-3-多个拦截器的执行顺序">11.3 多个拦截器的执行顺序</h3>
<p>a&gt;若每个拦截器的preHandle()都返回true</p>
<p>此时多个拦截器的执行顺序和拦截器在SpringMVC的配置文件的配置顺序有关：</p>
<p>preHandle()会按照配置的顺序执行，而postHandle()和afterComplation()会按照配置的反序执行</p>
<p>b&gt;若某个拦截器的preHandle()返回了false</p>
<p>preHandle()返回false和它之前的拦截器的preHandle()都会执行，postHandle()都不执行，返回false的拦截器之前的拦截器的afterComplation()会执行</p>
<h2 id="12-异常处理器">12 异常处理器</h2>
<h3 id="1、基于配置的异常处理">1、基于配置的异常处理</h3>
<p>SpringMVC提供了一个处理控制器方法执行过程中所出现的异常的接口：HandlerExceptionResolver</p>
<p>HandlerExceptionResolver接口的实现类有：DefaultHandlerExceptionResolver和SimpleMappingExceptionResolver</p>
<p>SpringMVC提供了自定义的异常处理器<code>SimpleMappingExceptionResolver</code>，使用方式：</p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">bean</span> <span class="attr">class</span>=<span class="string">&quot;org.springframework.web.servlet.handler.SimpleMappingExceptionResolver&quot;</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">property</span> <span class="attr">name</span>=<span class="string">&quot;exceptionMappings&quot;</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">props</span>&gt;</span></span><br><span class="line">        	<span class="comment">&lt;!--</span></span><br><span class="line"><span class="comment">        		properties的键表示处理器方法执行过程中出现的异常</span></span><br><span class="line"><span class="comment">        		properties的值表示若出现指定异常时，设置一个新的视图名称，跳转到指定页面</span></span><br><span class="line"><span class="comment">        	--&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">prop</span> <span class="attr">key</span>=<span class="string">&quot;java.lang.ArithmeticException&quot;</span>&gt;</span>error<span class="tag">&lt;/<span class="name">prop</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;/<span class="name">props</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">property</span>&gt;</span></span><br><span class="line">    <span class="comment">&lt;!--</span></span><br><span class="line"><span class="comment">    	exceptionAttribute属性设置一个属性名，将出现的异常信息在请求域中进行共享</span></span><br><span class="line"><span class="comment">    --&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">property</span> <span class="attr">name</span>=<span class="string">&quot;exceptionAttribute&quot;</span> <span class="attr">value</span>=<span class="string">&quot;ex&quot;</span>&gt;</span><span class="tag">&lt;/<span class="name">property</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">bean</span>&gt;</span></span><br></pre></td></tr></table></figure>
<h3 id="2、基于注解的异常处理">2、基于注解的异常处理</h3>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//@ControllerAdvice将当前类标识为异常处理的组件</span></span><br><span class="line"><span class="meta">@ControllerAdvice</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">ExceptionController</span> &#123;</span><br><span class="line"></span><br><span class="line">    <span class="comment">//@ExceptionHandler用于设置所标识方法处理的异常</span></span><br><span class="line">    <span class="meta">@ExceptionHandler(ArithmeticException.class)</span></span><br><span class="line">    <span class="comment">//ex表示当前请求处理中出现的异常对象</span></span><br><span class="line">    <span class="keyword">public</span> String <span class="title function_">handleArithmeticException</span><span class="params">(Exception ex, Model model)</span>&#123;</span><br><span class="line">        model.addAttribute(<span class="string">&quot;ex&quot;</span>, ex);</span><br><span class="line">        <span class="keyword">return</span> <span class="string">&quot;error&quot;</span>;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<h2 id="13-注解配置SpringMVC">13 注解配置SpringMVC</h2>
<p>使用配置类和注解代替web.xml和SpringMVC配置文件的功能</p>
<h3 id="1、创建初始化类，代替web-xml">1、创建初始化类，代替web.xml</h3>
<p>在Servlet3.0环境中，容器会在类路径中查找实现javax.servlet.ServletContainerInitializer接口的类，如果找到的话就用它来配置Servlet容器（就是Tomcat）。可以用这个类代替web.xml。<br>
Spring提供了这个接口的实现，名为SpringServletContainerInitializer，这个类反过来又会查找实现WebApplicationInitializer的类并将配置的任务交给它们来完成。Spring3.2引入了一个便利的WebApplicationInitializer基础实现，名为AbstractAnnotationConfigDispatcherServletInitializer，当我们的类扩展了AbstractAnnotationConfigDispatcherServletInitializer并将其部署到Servlet3.0容器的时候，容器会自动发现它，并用它来配置Servlet上下文。</p>
<p>总结一句话：如果用类代替web.xml文件，需要这个类去继承<code>AbstractAnnotationConfigDispatcherServletInitializer</code></p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">WebInit</span> <span class="keyword">extends</span> <span class="title class_">AbstractAnnotationConfigDispatcherServletInitializer</span> &#123;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 指定spring的配置类</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@return</span></span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="keyword">protected</span> Class&lt;?&gt;[] getRootConfigClasses() &#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="keyword">new</span> <span class="title class_">Class</span>[]&#123;SpringConfig.class&#125;;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 指定SpringMVC的配置类</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@return</span></span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="keyword">protected</span> Class&lt;?&gt;[] getServletConfigClasses() &#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="keyword">new</span> <span class="title class_">Class</span>[]&#123;WebConfig.class&#125;;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 指定DispatcherServlet的映射规则，即url-pattern</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@return</span></span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="keyword">protected</span> String[] getServletMappings() &#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="keyword">new</span> <span class="title class_">String</span>[]&#123;<span class="string">&quot;/&quot;</span>&#125;;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 添加过滤器</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@return</span></span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="keyword">protected</span> Filter[] getServletFilters() &#123;</span><br><span class="line">        <span class="type">CharacterEncodingFilter</span> <span class="variable">encodingFilter</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">CharacterEncodingFilter</span>();</span><br><span class="line">        encodingFilter.setEncoding(<span class="string">&quot;UTF-8&quot;</span>);</span><br><span class="line">        encodingFilter.setForceRequestEncoding(<span class="literal">true</span>);</span><br><span class="line">        <span class="type">HiddenHttpMethodFilter</span> <span class="variable">hiddenHttpMethodFilter</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">HiddenHttpMethodFilter</span>();</span><br><span class="line">        <span class="keyword">return</span> <span class="keyword">new</span> <span class="title class_">Filter</span>[]&#123;encodingFilter, hiddenHttpMethodFilter&#125;;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<h3 id="2、创建SpringConfig配置类，代替spring的配置文件">2、创建SpringConfig配置类，代替spring的配置文件</h3>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@Configuration</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">SpringConfig</span> &#123;</span><br><span class="line">	<span class="comment">//ssm整合之后，spring的配置信息写在此类中</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<h3 id="3、创建WebConfig配置类，代替SpringMVC的配置文件">3、创建WebConfig配置类，代替SpringMVC的配置文件</h3>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@Author</span>: zyl</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@Date</span>: 2021/08/24/17:14</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@Description</span>: 代替SpringMVC的配置文件</span></span><br><span class="line"><span class="comment"> *  1、扫描组件</span></span><br><span class="line"><span class="comment"> *  2、视图解析器</span></span><br><span class="line"><span class="comment"> *  3、view-controller</span></span><br><span class="line"><span class="comment"> *  4、default-servlet-handler</span></span><br><span class="line"><span class="comment"> *  5、mvc注解驱动</span></span><br><span class="line"><span class="comment"> *  6、文件上传解析器</span></span><br><span class="line"><span class="comment"> *  7、异常处理</span></span><br><span class="line"><span class="comment"> *  8、拦截器</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="comment">//将当前类表示为一个配置类</span></span><br><span class="line"><span class="meta">@Configuration</span></span><br><span class="line"><span class="comment">//1、扫描组件</span></span><br><span class="line"><span class="meta">@ComponentScan(&quot;com.atguigu.mvc&quot;)</span></span><br><span class="line"><span class="comment">//5、mvc注解驱动</span></span><br><span class="line"><span class="meta">@EnableWebMvc</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">WebConfig</span> <span class="keyword">implements</span> <span class="title class_">WebMvcConfigurer</span> &#123;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">    <span class="comment">//4、default-servlet-handler</span></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">configureDefaultServletHandling</span><span class="params">(DefaultServletHandlerConfigurer configurer)</span> &#123;</span><br><span class="line">        configurer.enable();</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">//8、拦截器</span></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">addInterceptors</span><span class="params">(InterceptorRegistry registry)</span> &#123;</span><br><span class="line">        registry.addInterceptor(<span class="keyword">new</span> <span class="title class_">TestInterceptor</span>())</span><br><span class="line">                .addPathPatterns(<span class="string">&quot;/**&quot;</span>)   <span class="comment">//配置拦截的路径</span></span><br><span class="line">                .excludePathPatterns(<span class="string">&quot;/&quot;</span>);<span class="comment">//排除的的路径</span></span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">//3、view-controller</span></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">addViewControllers</span><span class="params">(ViewControllerRegistry registry)</span> &#123;</span><br><span class="line">        registry.addViewController(<span class="string">&quot;/hello&quot;</span>)</span><br><span class="line">                .setViewName(<span class="string">&quot;hello&quot;</span>);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">//6、文件上传解析器</span></span><br><span class="line">    <span class="meta">@Bean</span></span><br><span class="line">    <span class="keyword">public</span> MultipartResolver <span class="title function_">multipartResolver</span><span class="params">()</span>&#123;</span><br><span class="line">        <span class="type">CommonsMultipartResolver</span> <span class="variable">commonsMultipartResolver</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">CommonsMultipartResolver</span>();</span><br><span class="line">        <span class="keyword">return</span> commonsMultipartResolver;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">//7、异常处理</span></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">configureHandlerExceptionResolvers</span><span class="params">(List&lt;HandlerExceptionResolver&gt; resolvers)</span> &#123;</span><br><span class="line"></span><br><span class="line">        <span class="type">SimpleMappingExceptionResolver</span> <span class="variable">exceptionResolver</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">SimpleMappingExceptionResolver</span>();</span><br><span class="line">        <span class="type">Properties</span> <span class="variable">prop</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">Properties</span>();</span><br><span class="line">        <span class="comment">//不能使用put方法，使用setProperty，使键值对都是字符串</span></span><br><span class="line">        prop.setProperty(<span class="string">&quot;java.lang.ArithmeticException&quot;</span>,<span class="string">&quot;error&quot;</span>);<span class="comment">//异常类型和跳转的页面名称</span></span><br><span class="line">        exceptionResolver.setExceptionMappings(prop);</span><br><span class="line">        exceptionResolver.setExceptionAttribute(<span class="string">&quot;exception&quot;</span>);<span class="comment">//把异常信息放到request共享域</span></span><br><span class="line">        resolvers.add(exceptionResolver);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">//========配置Thymeleaf视图解析器==============</span></span><br><span class="line">    <span class="comment">//配置生成模板解析器</span></span><br><span class="line">    <span class="meta">@Bean</span></span><br><span class="line">    <span class="keyword">public</span> ITemplateResolver <span class="title function_">templateResolver</span><span class="params">()</span> &#123;</span><br><span class="line">        <span class="type">WebApplicationContext</span> <span class="variable">webApplicationContext</span> <span class="operator">=</span> ContextLoader.getCurrentWebApplicationContext();</span><br><span class="line">        <span class="comment">// ServletContextTemplateResolver需要一个ServletContext作为构造参数，可通过WebApplicationContext 的方法获得</span></span><br><span class="line">        <span class="type">ServletContextTemplateResolver</span> <span class="variable">templateResolver</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">ServletContextTemplateResolver</span>(</span><br><span class="line">                webApplicationContext.getServletContext());</span><br><span class="line">        templateResolver.setPrefix(<span class="string">&quot;/WEB-INF/templates/&quot;</span>);</span><br><span class="line">        templateResolver.setSuffix(<span class="string">&quot;.html&quot;</span>);</span><br><span class="line">        templateResolver.setCharacterEncoding(<span class="string">&quot;UTF-8&quot;</span>);</span><br><span class="line">        templateResolver.setTemplateMode(TemplateMode.HTML);</span><br><span class="line">        <span class="keyword">return</span> templateResolver;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">//生成模板引擎并为模板引擎注入模板解析器</span></span><br><span class="line">    <span class="comment">//方法的形参是自动装配，按照类型自动装配</span></span><br><span class="line">    <span class="meta">@Bean</span></span><br><span class="line">    <span class="keyword">public</span> SpringTemplateEngine <span class="title function_">templateEngine</span><span class="params">(ITemplateResolver templateResolver)</span> &#123;</span><br><span class="line">        <span class="type">SpringTemplateEngine</span> <span class="variable">templateEngine</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">SpringTemplateEngine</span>();</span><br><span class="line">        templateEngine.setTemplateResolver(templateResolver);</span><br><span class="line">        <span class="keyword">return</span> templateEngine;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">//生成视图解析器并未解析器注入模板引擎</span></span><br><span class="line">    <span class="meta">@Bean</span></span><br><span class="line">    <span class="keyword">public</span> ViewResolver <span class="title function_">viewResolver</span><span class="params">(SpringTemplateEngine templateEngine)</span> &#123;</span><br><span class="line">        <span class="type">ThymeleafViewResolver</span> <span class="variable">viewResolver</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">ThymeleafViewResolver</span>();</span><br><span class="line">        viewResolver.setCharacterEncoding(<span class="string">&quot;UTF-8&quot;</span>);</span><br><span class="line">        viewResolver.setTemplateEngine(templateEngine);</span><br><span class="line">        <span class="keyword">return</span> viewResolver;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="comment">//====================================</span></span><br><span class="line"></span><br><span class="line"></span><br><span class="line">&#125;</span><br><span class="line"></span><br></pre></td></tr></table></figure>
<h3 id="4、测试功能">4、测试功能</h3>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@RequestMapping(&quot;/&quot;)</span></span><br><span class="line"><span class="keyword">public</span> String <span class="title function_">index</span><span class="params">()</span>&#123;</span><br><span class="line">    <span class="keyword">return</span> <span class="string">&quot;index&quot;</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<h2 id="14-SpringMVC执行流程">14 SpringMVC执行流程</h2>
<h3 id="1、SpringMVC常用组件">1、SpringMVC常用组件</h3>
<ul>
<li>DispatcherServlet：<strong>前端控制器</strong>，不需要工程师开发，由框架提供</li>
</ul>
<p>作用：统一处理请求和响应，整个流程控制的中心，由它调用其它组件处理用户的请求</p>
<ul>
<li>HandlerMapping：<strong>处理器映射器</strong>，不需要工程师开发，由框架提供</li>
</ul>
<p>作用：根据请求的url、method等信息查找Handler，即控制器方法</p>
<ul>
<li>Handler：<strong>处理器</strong>，需要工程师开发</li>
</ul>
<p>作用：在DispatcherServlet的控制下Handler对具体的用户请求进行处理</p>
<ul>
<li>HandlerAdapter：<strong>处理器适配器</strong>，不需要工程师开发，由框架提供</li>
</ul>
<p>作用：通过HandlerAdapter对处理器（控制器方法）进行执行</p>
<ul>
<li>ViewResolver：<strong>视图解析器</strong>，不需要工程师开发，由框架提供</li>
</ul>
<p>作用：进行视图解析，得到相应的视图，例如：ThymeleafView、InternalResourceView、RedirectView</p>
<ul>
<li>View：<strong>视图</strong></li>
</ul>
<p>作用：将模型数据通过页面展示给用户</p>
<h3 id="2、DispatcherServlet初始化过程">2、DispatcherServlet初始化过程</h3>
<p>DispatcherServlet 本质上是一个 Servlet，所以天然的遵循 Servlet 的生命周期。所以宏观上是 Servlet 生命周期来进行调度。</p>
<p><img src="https://zylai-cloud-pic-1306915061.cos.ap-nanjing.myqcloud.com/images01/SpringMVC.assets/image-20220801153212004.png" alt="image-20220801153212004"></p>
<p>在FrameworkServlet的initServletBean()方法中，调用了initWebApplicationContext()方法，下面就需要看如何初始化IOC容器</p>
<h5 id="a-初始化WebApplicationContext">a&gt;初始化WebApplicationContext</h5>
<p>所在类：org.springframework.web.servlet.FrameworkServlet</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">protected</span> WebApplicationContext <span class="title function_">initWebApplicationContext</span><span class="params">()</span> &#123;</span><br><span class="line">    <span class="type">WebApplicationContext</span> <span class="variable">rootContext</span> <span class="operator">=</span></span><br><span class="line">        WebApplicationContextUtils.getWebApplicationContext(getServletContext());</span><br><span class="line">    <span class="type">WebApplicationContext</span> <span class="variable">wac</span> <span class="operator">=</span> <span class="literal">null</span>;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">if</span> (<span class="built_in">this</span>.webApplicationContext != <span class="literal">null</span>) &#123;</span><br><span class="line">        <span class="comment">// A context instance was injected at construction time -&gt; use it</span></span><br><span class="line">        wac = <span class="built_in">this</span>.webApplicationContext;</span><br><span class="line">        <span class="keyword">if</span> (wac <span class="keyword">instanceof</span> ConfigurableWebApplicationContext) &#123;</span><br><span class="line">            <span class="type">ConfigurableWebApplicationContext</span> <span class="variable">cwac</span> <span class="operator">=</span> (ConfigurableWebApplicationContext) wac;</span><br><span class="line">            <span class="keyword">if</span> (!cwac.isActive()) &#123;</span><br><span class="line">                <span class="comment">// The context has not yet been refreshed -&gt; provide services such as</span></span><br><span class="line">                <span class="comment">// setting the parent context, setting the application context id, etc</span></span><br><span class="line">                <span class="keyword">if</span> (cwac.getParent() == <span class="literal">null</span>) &#123;</span><br><span class="line">                    <span class="comment">// The context instance was injected without an explicit parent -&gt; set</span></span><br><span class="line">                    <span class="comment">// the root application context (if any; may be null) as the parent</span></span><br><span class="line">                    cwac.setParent(rootContext);</span><br><span class="line">                &#125;</span><br><span class="line">                configureAndRefreshWebApplicationContext(cwac);</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">if</span> (wac == <span class="literal">null</span>) &#123;</span><br><span class="line">        <span class="comment">// No context instance was injected at construction time -&gt; see if one</span></span><br><span class="line">        <span class="comment">// has been registered in the servlet context. If one exists, it is assumed</span></span><br><span class="line">        <span class="comment">// that the parent context (if any) has already been set and that the</span></span><br><span class="line">        <span class="comment">// user has performed any initialization such as setting the context id</span></span><br><span class="line">        wac = findWebApplicationContext();</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">if</span> (wac == <span class="literal">null</span>) &#123;</span><br><span class="line">        <span class="comment">// No context instance is defined for this servlet -&gt; create a local one</span></span><br><span class="line">        <span class="comment">// 创建WebApplicationContext</span></span><br><span class="line">        wac = createWebApplicationContext(rootContext);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">if</span> (!<span class="built_in">this</span>.refreshEventReceived) &#123;</span><br><span class="line">        <span class="comment">// Either the context is not a ConfigurableApplicationContext with refresh</span></span><br><span class="line">        <span class="comment">// support or the context injected at construction time had already been</span></span><br><span class="line">        <span class="comment">// refreshed -&gt; trigger initial onRefresh manually here.</span></span><br><span class="line">        <span class="keyword">synchronized</span> (<span class="built_in">this</span>.onRefreshMonitor) &#123;</span><br><span class="line">            <span class="comment">// 刷新WebApplicationContext</span></span><br><span class="line">            onRefresh(wac);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">if</span> (<span class="built_in">this</span>.publishContext) &#123;</span><br><span class="line">        <span class="comment">// Publish the context as a servlet context attribute.</span></span><br><span class="line">        <span class="comment">// 将IOC容器在应用域共享</span></span><br><span class="line">        <span class="type">String</span> <span class="variable">attrName</span> <span class="operator">=</span> getServletContextAttributeName();</span><br><span class="line">        getServletContext().setAttribute(attrName, wac);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">return</span> wac;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<h5 id="b-创建WebApplicationContext">b&gt;创建WebApplicationContext</h5>
<p>所在类：org.springframework.web.servlet.FrameworkServlet</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">protected</span> WebApplicationContext <span class="title function_">createWebApplicationContext</span><span class="params">(<span class="meta">@Nullable</span> ApplicationContext parent)</span> &#123;</span><br><span class="line">    Class&lt;?&gt; contextClass = getContextClass();</span><br><span class="line">    <span class="keyword">if</span> (!ConfigurableWebApplicationContext.class.isAssignableFrom(contextClass)) &#123;</span><br><span class="line">        <span class="keyword">throw</span> <span class="keyword">new</span> <span class="title class_">ApplicationContextException</span>(</span><br><span class="line">            <span class="string">&quot;Fatal initialization error in servlet with name &#x27;&quot;</span> + getServletName() +</span><br><span class="line">            <span class="string">&quot;&#x27;: custom WebApplicationContext class [&quot;</span> + contextClass.getName() +</span><br><span class="line">            <span class="string">&quot;] is not of type ConfigurableWebApplicationContext&quot;</span>);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="comment">// 通过反射创建 IOC 容器对象</span></span><br><span class="line">    <span class="type">ConfigurableWebApplicationContext</span> <span class="variable">wac</span> <span class="operator">=</span></span><br><span class="line">        (ConfigurableWebApplicationContext) BeanUtils.instantiateClass(contextClass);</span><br><span class="line"></span><br><span class="line">    wac.setEnvironment(getEnvironment());</span><br><span class="line">    <span class="comment">// 设置父容器</span></span><br><span class="line">    wac.setParent(parent);</span><br><span class="line">    <span class="type">String</span> <span class="variable">configLocation</span> <span class="operator">=</span> getContextConfigLocation();</span><br><span class="line">    <span class="keyword">if</span> (configLocation != <span class="literal">null</span>) &#123;</span><br><span class="line">        wac.setConfigLocation(configLocation);</span><br><span class="line">    &#125;</span><br><span class="line">    configureAndRefreshWebApplicationContext(wac);</span><br><span class="line"></span><br><span class="line">    <span class="keyword">return</span> wac;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<h5 id="c-DispatcherServlet初始化策略">c&gt;DispatcherServlet初始化策略</h5>
<p>FrameworkServlet创建WebApplicationContext后，刷新容器，调用onRefresh(wac)，此方法在DispatcherServlet中进行了重写，调用了initStrategies(context)方法，初始化策略，即初始化DispatcherServlet的各个组件</p>
<p>所在类：org.springframework.web.servlet.DispatcherServlet</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">protected</span> <span class="keyword">void</span> <span class="title function_">initStrategies</span><span class="params">(ApplicationContext context)</span> &#123;</span><br><span class="line">   initMultipartResolver(context);</span><br><span class="line">   initLocaleResolver(context);</span><br><span class="line">   initThemeResolver(context);</span><br><span class="line">   initHandlerMappings(context);</span><br><span class="line">   initHandlerAdapters(context);</span><br><span class="line">   initHandlerExceptionResolvers(context);</span><br><span class="line">   initRequestToViewNameTranslator(context);</span><br><span class="line">   initViewResolvers(context);</span><br><span class="line">   initFlashMapManager(context);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<h3 id="3、DispatcherServlet调用组件处理请求">3、DispatcherServlet调用组件处理请求</h3>
<h5 id="a-processRequest">a&gt;processRequest()</h5>
<p>FrameworkServlet重写HttpServlet中的service()和doXxx()，这些方法中调用了processRequest(request, response)</p>
<p>所在类：org.springframework.web.servlet.FrameworkServlet</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">protected</span> <span class="keyword">final</span> <span class="keyword">void</span> <span class="title function_">processRequest</span><span class="params">(HttpServletRequest request, HttpServletResponse response)</span></span><br><span class="line">    <span class="keyword">throws</span> ServletException, IOException &#123;</span><br><span class="line"></span><br><span class="line">    <span class="type">long</span> <span class="variable">startTime</span> <span class="operator">=</span> System.currentTimeMillis();</span><br><span class="line">    <span class="type">Throwable</span> <span class="variable">failureCause</span> <span class="operator">=</span> <span class="literal">null</span>;</span><br><span class="line"></span><br><span class="line">    <span class="type">LocaleContext</span> <span class="variable">previousLocaleContext</span> <span class="operator">=</span> LocaleContextHolder.getLocaleContext();</span><br><span class="line">    <span class="type">LocaleContext</span> <span class="variable">localeContext</span> <span class="operator">=</span> buildLocaleContext(request);</span><br><span class="line"></span><br><span class="line">    <span class="type">RequestAttributes</span> <span class="variable">previousAttributes</span> <span class="operator">=</span> RequestContextHolder.getRequestAttributes();</span><br><span class="line">    <span class="type">ServletRequestAttributes</span> <span class="variable">requestAttributes</span> <span class="operator">=</span> buildRequestAttributes(request, response, previousAttributes);</span><br><span class="line"></span><br><span class="line">    <span class="type">WebAsyncManager</span> <span class="variable">asyncManager</span> <span class="operator">=</span> WebAsyncUtils.getAsyncManager(request);</span><br><span class="line">    asyncManager.registerCallableInterceptor(FrameworkServlet.class.getName(), <span class="keyword">new</span> <span class="title class_">RequestBindingInterceptor</span>());</span><br><span class="line"></span><br><span class="line">    initContextHolders(request, localeContext, requestAttributes);</span><br><span class="line"></span><br><span class="line">    <span class="keyword">try</span> &#123;</span><br><span class="line">		<span class="comment">// 执行服务，doService()是一个抽象方法，在DispatcherServlet中进行了重写</span></span><br><span class="line">        doService(request, response);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">catch</span> (ServletException | IOException ex) &#123;</span><br><span class="line">        failureCause = ex;</span><br><span class="line">        <span class="keyword">throw</span> ex;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">catch</span> (Throwable ex) &#123;</span><br><span class="line">        failureCause = ex;</span><br><span class="line">        <span class="keyword">throw</span> <span class="keyword">new</span> <span class="title class_">NestedServletException</span>(<span class="string">&quot;Request processing failed&quot;</span>, ex);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">finally</span> &#123;</span><br><span class="line">        resetContextHolders(request, previousLocaleContext, previousAttributes);</span><br><span class="line">        <span class="keyword">if</span> (requestAttributes != <span class="literal">null</span>) &#123;</span><br><span class="line">            requestAttributes.requestCompleted();</span><br><span class="line">        &#125;</span><br><span class="line">        logResult(request, response, failureCause, asyncManager);</span><br><span class="line">        publishRequestHandledEvent(request, response, startTime, failureCause);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<h5 id="b-doService">b&gt;doService()</h5>
<p>所在类：org.springframework.web.servlet.DispatcherServlet</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@Override</span></span><br><span class="line"><span class="keyword">protected</span> <span class="keyword">void</span> <span class="title function_">doService</span><span class="params">(HttpServletRequest request, HttpServletResponse response)</span> <span class="keyword">throws</span> Exception &#123;</span><br><span class="line">    logRequest(request);</span><br><span class="line"></span><br><span class="line">    <span class="comment">// Keep a snapshot of the request attributes in case of an include,</span></span><br><span class="line">    <span class="comment">// to be able to restore the original attributes after the include.</span></span><br><span class="line">    Map&lt;String, Object&gt; attributesSnapshot = <span class="literal">null</span>;</span><br><span class="line">    <span class="keyword">if</span> (WebUtils.isIncludeRequest(request)) &#123;</span><br><span class="line">        attributesSnapshot = <span class="keyword">new</span> <span class="title class_">HashMap</span>&lt;&gt;();</span><br><span class="line">        Enumeration&lt;?&gt; attrNames = request.getAttributeNames();</span><br><span class="line">        <span class="keyword">while</span> (attrNames.hasMoreElements()) &#123;</span><br><span class="line">            <span class="type">String</span> <span class="variable">attrName</span> <span class="operator">=</span> (String) attrNames.nextElement();</span><br><span class="line">            <span class="keyword">if</span> (<span class="built_in">this</span>.cleanupAfterInclude || attrName.startsWith(DEFAULT_STRATEGIES_PREFIX)) &#123;</span><br><span class="line">                attributesSnapshot.put(attrName, request.getAttribute(attrName));</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// Make framework objects available to handlers and view objects.</span></span><br><span class="line">    request.setAttribute(WEB_APPLICATION_CONTEXT_ATTRIBUTE, getWebApplicationContext());</span><br><span class="line">    request.setAttribute(LOCALE_RESOLVER_ATTRIBUTE, <span class="built_in">this</span>.localeResolver);</span><br><span class="line">    request.setAttribute(THEME_RESOLVER_ATTRIBUTE, <span class="built_in">this</span>.themeResolver);</span><br><span class="line">    request.setAttribute(THEME_SOURCE_ATTRIBUTE, getThemeSource());</span><br><span class="line"></span><br><span class="line">    <span class="keyword">if</span> (<span class="built_in">this</span>.flashMapManager != <span class="literal">null</span>) &#123;</span><br><span class="line">        <span class="type">FlashMap</span> <span class="variable">inputFlashMap</span> <span class="operator">=</span> <span class="built_in">this</span>.flashMapManager.retrieveAndUpdate(request, response);</span><br><span class="line">        <span class="keyword">if</span> (inputFlashMap != <span class="literal">null</span>) &#123;</span><br><span class="line">            request.setAttribute(INPUT_FLASH_MAP_ATTRIBUTE, Collections.unmodifiableMap(inputFlashMap));</span><br><span class="line">        &#125;</span><br><span class="line">        request.setAttribute(OUTPUT_FLASH_MAP_ATTRIBUTE, <span class="keyword">new</span> <span class="title class_">FlashMap</span>());</span><br><span class="line">        request.setAttribute(FLASH_MAP_MANAGER_ATTRIBUTE, <span class="built_in">this</span>.flashMapManager);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="type">RequestPath</span> <span class="variable">requestPath</span> <span class="operator">=</span> <span class="literal">null</span>;</span><br><span class="line">    <span class="keyword">if</span> (<span class="built_in">this</span>.parseRequestPath &amp;&amp; !ServletRequestPathUtils.hasParsedRequestPath(request)) &#123;</span><br><span class="line">        requestPath = ServletRequestPathUtils.parseAndCache(request);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">try</span> &#123;</span><br><span class="line">        <span class="comment">// 处理请求和响应</span></span><br><span class="line">        doDispatch(request, response);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">finally</span> &#123;</span><br><span class="line">        <span class="keyword">if</span> (!WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted()) &#123;</span><br><span class="line">            <span class="comment">// Restore the original attribute snapshot, in case of an include.</span></span><br><span class="line">            <span class="keyword">if</span> (attributesSnapshot != <span class="literal">null</span>) &#123;</span><br><span class="line">                restoreAttributesAfterInclude(request, attributesSnapshot);</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">if</span> (requestPath != <span class="literal">null</span>) &#123;</span><br><span class="line">            ServletRequestPathUtils.clearParsedRequestPath(request);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<h5 id="c-doDispatch">c&gt;doDispatch()</h5>
<p>所在类：org.springframework.web.servlet.DispatcherServlet</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">protected</span> <span class="keyword">void</span> <span class="title function_">doDispatch</span><span class="params">(HttpServletRequest request, HttpServletResponse response)</span> <span class="keyword">throws</span> Exception &#123;</span><br><span class="line">    <span class="type">HttpServletRequest</span> <span class="variable">processedRequest</span> <span class="operator">=</span> request;</span><br><span class="line">    <span class="type">HandlerExecutionChain</span> <span class="variable">mappedHandler</span> <span class="operator">=</span> <span class="literal">null</span>;</span><br><span class="line">    <span class="type">boolean</span> <span class="variable">multipartRequestParsed</span> <span class="operator">=</span> <span class="literal">false</span>;</span><br><span class="line"></span><br><span class="line">    <span class="type">WebAsyncManager</span> <span class="variable">asyncManager</span> <span class="operator">=</span> WebAsyncUtils.getAsyncManager(request);</span><br><span class="line"></span><br><span class="line">    <span class="keyword">try</span> &#123;</span><br><span class="line">        <span class="type">ModelAndView</span> <span class="variable">mv</span> <span class="operator">=</span> <span class="literal">null</span>;</span><br><span class="line">        <span class="type">Exception</span> <span class="variable">dispatchException</span> <span class="operator">=</span> <span class="literal">null</span>;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">try</span> &#123;</span><br><span class="line">            processedRequest = checkMultipart(request);</span><br><span class="line">            multipartRequestParsed = (processedRequest != request);</span><br><span class="line"></span><br><span class="line">            <span class="comment">// Determine handler for the current request.</span></span><br><span class="line">            <span class="comment">/*</span></span><br><span class="line"><span class="comment">            	mappedHandler：调用链</span></span><br><span class="line"><span class="comment">                包含handler、interceptorList、interceptorIndex</span></span><br><span class="line"><span class="comment">            	handler：浏览器发送的请求所匹配的控制器方法</span></span><br><span class="line"><span class="comment">            	interceptorList：处理控制器方法的所有拦截器集合</span></span><br><span class="line"><span class="comment">            	interceptorIndex：拦截器索引，控制拦截器afterCompletion()的执行</span></span><br><span class="line"><span class="comment">            */</span></span><br><span class="line">            mappedHandler = getHandler(processedRequest);</span><br><span class="line">            <span class="keyword">if</span> (mappedHandler == <span class="literal">null</span>) &#123;</span><br><span class="line">                noHandlerFound(processedRequest, response);</span><br><span class="line">                <span class="keyword">return</span>;</span><br><span class="line">            &#125;</span><br><span class="line"></span><br><span class="line">            <span class="comment">// Determine handler adapter for the current request.</span></span><br><span class="line">           	<span class="comment">// 通过控制器方法创建相应的处理器适配器，调用所对应的控制器方法</span></span><br><span class="line">            <span class="type">HandlerAdapter</span> <span class="variable">ha</span> <span class="operator">=</span> getHandlerAdapter(mappedHandler.getHandler());</span><br><span class="line"></span><br><span class="line">            <span class="comment">// Process last-modified header, if supported by the handler.</span></span><br><span class="line">            <span class="type">String</span> <span class="variable">method</span> <span class="operator">=</span> request.getMethod();</span><br><span class="line">            <span class="type">boolean</span> <span class="variable">isGet</span> <span class="operator">=</span> <span class="string">&quot;GET&quot;</span>.equals(method);</span><br><span class="line">            <span class="keyword">if</span> (isGet || <span class="string">&quot;HEAD&quot;</span>.equals(method)) &#123;</span><br><span class="line">                <span class="type">long</span> <span class="variable">lastModified</span> <span class="operator">=</span> ha.getLastModified(request, mappedHandler.getHandler());</span><br><span class="line">                <span class="keyword">if</span> (<span class="keyword">new</span> <span class="title class_">ServletWebRequest</span>(request, response).checkNotModified(lastModified) &amp;&amp; isGet) &#123;</span><br><span class="line">                    <span class="keyword">return</span>;</span><br><span class="line">                &#125;</span><br><span class="line">            &#125;</span><br><span class="line">			</span><br><span class="line">            <span class="comment">// 调用拦截器的preHandle()</span></span><br><span class="line">            <span class="keyword">if</span> (!mappedHandler.applyPreHandle(processedRequest, response)) &#123;</span><br><span class="line">                <span class="keyword">return</span>;</span><br><span class="line">            &#125;</span><br><span class="line"></span><br><span class="line">            <span class="comment">// Actually invoke the handler.</span></span><br><span class="line">            <span class="comment">// 由处理器适配器调用具体的控制器方法，最终获得ModelAndView对象</span></span><br><span class="line">            mv = ha.handle(processedRequest, response, mappedHandler.getHandler());</span><br><span class="line"></span><br><span class="line">            <span class="keyword">if</span> (asyncManager.isConcurrentHandlingStarted()) &#123;</span><br><span class="line">                <span class="keyword">return</span>;</span><br><span class="line">            &#125;</span><br><span class="line"></span><br><span class="line">            applyDefaultViewName(processedRequest, mv);</span><br><span class="line">            <span class="comment">// 调用拦截器的postHandle()</span></span><br><span class="line">            mappedHandler.applyPostHandle(processedRequest, response, mv);</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">catch</span> (Exception ex) &#123;</span><br><span class="line">            dispatchException = ex;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">catch</span> (Throwable err) &#123;</span><br><span class="line">            <span class="comment">// As of 4.3, we&#x27;re processing Errors thrown from handler methods as well,</span></span><br><span class="line">            <span class="comment">// making them available for @ExceptionHandler methods and other scenarios.</span></span><br><span class="line">            dispatchException = <span class="keyword">new</span> <span class="title class_">NestedServletException</span>(<span class="string">&quot;Handler dispatch failed&quot;</span>, err);</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="comment">// 后续处理：处理模型数据和渲染视图</span></span><br><span class="line">        processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">catch</span> (Exception ex) &#123;</span><br><span class="line">        triggerAfterCompletion(processedRequest, response, mappedHandler, ex);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">catch</span> (Throwable err) &#123;</span><br><span class="line">        triggerAfterCompletion(processedRequest, response, mappedHandler,</span><br><span class="line">                               <span class="keyword">new</span> <span class="title class_">NestedServletException</span>(<span class="string">&quot;Handler processing failed&quot;</span>, err));</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">finally</span> &#123;</span><br><span class="line">        <span class="keyword">if</span> (asyncManager.isConcurrentHandlingStarted()) &#123;</span><br><span class="line">            <span class="comment">// Instead of postHandle and afterCompletion</span></span><br><span class="line">            <span class="keyword">if</span> (mappedHandler != <span class="literal">null</span>) &#123;</span><br><span class="line">                mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">else</span> &#123;</span><br><span class="line">            <span class="comment">// Clean up any resources used by a multipart request.</span></span><br><span class="line">            <span class="keyword">if</span> (multipartRequestParsed) &#123;</span><br><span class="line">                cleanupMultipart(processedRequest);</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<h5 id="d-processDispatchResult">d&gt;processDispatchResult()</h5>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">private</span> <span class="keyword">void</span> <span class="title function_">processDispatchResult</span><span class="params">(HttpServletRequest request, HttpServletResponse response,</span></span><br><span class="line"><span class="params">                                   <span class="meta">@Nullable</span> HandlerExecutionChain mappedHandler, <span class="meta">@Nullable</span> ModelAndView mv,</span></span><br><span class="line"><span class="params">                                   <span class="meta">@Nullable</span> Exception exception)</span> <span class="keyword">throws</span> Exception &#123;</span><br><span class="line"></span><br><span class="line">    <span class="type">boolean</span> <span class="variable">errorView</span> <span class="operator">=</span> <span class="literal">false</span>;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">if</span> (exception != <span class="literal">null</span>) &#123;</span><br><span class="line">        <span class="keyword">if</span> (exception <span class="keyword">instanceof</span> ModelAndViewDefiningException) &#123;</span><br><span class="line">            logger.debug(<span class="string">&quot;ModelAndViewDefiningException encountered&quot;</span>, exception);</span><br><span class="line">            mv = ((ModelAndViewDefiningException) exception).getModelAndView();</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">else</span> &#123;</span><br><span class="line">            <span class="type">Object</span> <span class="variable">handler</span> <span class="operator">=</span> (mappedHandler != <span class="literal">null</span> ? mappedHandler.getHandler() : <span class="literal">null</span>);</span><br><span class="line">            mv = processHandlerException(request, response, handler, exception);</span><br><span class="line">            errorView = (mv != <span class="literal">null</span>);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// Did the handler return a view to render?</span></span><br><span class="line">    <span class="keyword">if</span> (mv != <span class="literal">null</span> &amp;&amp; !mv.wasCleared()) &#123;</span><br><span class="line">        <span class="comment">// 处理模型数据和渲染视图</span></span><br><span class="line">        render(mv, request, response);</span><br><span class="line">        <span class="keyword">if</span> (errorView) &#123;</span><br><span class="line">            WebUtils.clearErrorRequestAttributes(request);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">else</span> &#123;</span><br><span class="line">        <span class="keyword">if</span> (logger.isTraceEnabled()) &#123;</span><br><span class="line">            logger.trace(<span class="string">&quot;No view rendering, null ModelAndView returned.&quot;</span>);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">if</span> (WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted()) &#123;</span><br><span class="line">        <span class="comment">// Concurrent handling started during a forward</span></span><br><span class="line">        <span class="keyword">return</span>;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">if</span> (mappedHandler != <span class="literal">null</span>) &#123;</span><br><span class="line">        <span class="comment">// Exception (if any) is already handled..</span></span><br><span class="line">        <span class="comment">// 调用拦截器的afterCompletion()</span></span><br><span class="line">        mappedHandler.triggerAfterCompletion(request, response, <span class="literal">null</span>);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<h3 id="4、SpringMVC的执行流程">4、SpringMVC的执行流程</h3>
<ol>
<li>
<p>用户向服务器发送请求，请求被SpringMVC 前端控制器 DispatcherServlet捕获。</p>
</li>
<li>
<p>DispatcherServlet对请求URL进行解析，得到请求资源标识符（URI），判断请求URI对应的映射：</p>
</li>
</ol>
<p>a) 不存在</p>
<p>i. 再判断是否配置了mvc:default-servlet-handler</p>
<p>ii. 如果没配置，则控制台报映射查找不到，客户端展示404错误</p>
<p><img src="https://zylai-cloud-pic-1306915061.cos.ap-nanjing.myqcloud.com/images01/SpringMVC.assets/image-20220801163513358.png" alt="image-20220801163513358"></p>
<p><img src="https://zylai-cloud-pic-1306915061.cos.ap-nanjing.myqcloud.com/images01/SpringMVC.assets/img007.png" alt="image-20210709214947432"></p>
<p>iii. 如果有配置，则访问目标资源（一般为静态资源，如：JS,CSS,HTML），找不到客户端也会展示404错误</p>
<p><img src="https://zylai-cloud-pic-1306915061.cos.ap-nanjing.myqcloud.com/images01/SpringMVC.assets/img008.png" alt="image-20210709215255693"></p>
<p><img src="https://zylai-cloud-pic-1306915061.cos.ap-nanjing.myqcloud.com/images01/SpringMVC.assets/img009.png" alt="image-20210709215336097"></p>
<p>b) 存在则执行下面的流程</p>
<ol start="3">
<li>
<p>根据该URI，调用HandlerMapping获得该Handler配置的所有相关的对象（包括Handler对象以及Handler对象对应的拦截器），最后以HandlerExecutionChain执行链对象的形式返回。</p>
</li>
<li>
<p>DispatcherServlet 根据获得的Handler，选择一个合适的HandlerAdapter。</p>
</li>
<li>
<p>如果成功获得HandlerAdapter，此时将开始执行拦截器的preHandler(…)方法【正向】</p>
</li>
<li>
<p>提取Request中的模型数据，填充Handler入参，开始执行Handler（Controller)方法，处理请求。在填充Handler的入参过程中，根据你的配置，Spring将帮你做一些额外的工作：</p>
</li>
</ol>
<p>a) HttpMessageConveter： 将请求消息（如Json、xml等数据）转换成一个对象，将对象转换为指定的响应信息</p>
<p>b) 数据转换：对请求消息进行数据转换。如String转换成Integer、Double等</p>
<p>c) 数据格式化：对请求消息进行数据格式化。 如将字符串转换成格式化数字或格式化日期等</p>
<p>d) 数据验证： 验证数据的有效性（长度、格式等），验证结果存储到BindingResult或Error中</p>
<ol start="7">
<li>
<p>Handler执行完成后，向DispatcherServlet 返回一个ModelAndView对象。</p>
</li>
<li>
<p>此时将开始执行拦截器的postHandle(…)方法【逆向】。</p>
</li>
<li>
<p>根据返回的ModelAndView（此时会判断是否存在异常：如果存在异常，则执行HandlerExceptionResolver进行异常处理）选择一个适合的ViewResolver进行视图解析，根据Model和View，来渲染视图。</p>
</li>
<li>
<p>渲染视图完毕执行拦截器的afterCompletion(…)方法【逆向】。</p>
</li>
<li>
<p>将渲染结果返回给客户端。</p>
</li>
</ol>
</article><div class="post-copyright"><div class="post-copyright__author"><span class="post-copyright-meta">文章作者: </span><span class="post-copyright-info"><a href="https://zhaoyunlai.gitee.io">zylai</a></span></div><div class="post-copyright__type"><span class="post-copyright-meta">文章链接: </span><span class="post-copyright-info"><a href="https://zhaoyunlai.gitee.io/posts/97f98a11ca37/">https://zhaoyunlai.gitee.io/posts/97f98a11ca37/</a></span></div><div class="post-copyright__notice"><span class="post-copyright-meta">版权声明: </span><span class="post-copyright-info">本博客所有文章除特别声明外，均采用 <a href="https://creativecommons.org/licenses/by-nc-sa/4.0/" target="_blank">CC BY-NC-SA 4.0</a> 许可协议。转载请注明来自 <a href="https://zhaoyunlai.gitee.io" target="_blank">zylai</a>！</span></div></div><div class="tag_share"><div class="post-meta__tag-list"><a class="post-meta__tags" href="/tags/%E6%A1%86%E6%9E%B6/">框架</a><a class="post-meta__tags" href="/tags/Spring-Framework/">Spring Framework</a><a class="post-meta__tags" href="/tags/web%E5%BA%94%E7%94%A8/">web应用</a></div><div class="post_share"><div class="social-share" data-image="https://zylai-cloud-pic-1306915061.cos.ap-nanjing.myqcloud.com/images01/SpringMVC.assets/SpringMVC-logo.png" data-sites="facebook,twitter,wechat,weibo,qq"></div><link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/butterfly-extsrc/sharejs/dist/css/share.min.css" media="print" onload="this.media='all'"><script src="https://cdn.jsdelivr.net/npm/butterfly-extsrc/sharejs/dist/js/social-share.min.js" defer></script></div></div><nav class="pagination-post" id="pagination"><div class="prev-post pull-left"><a href="/posts/91d12734b70c/"><img class="prev-cover" src="https://zylai-cloud-pic-1306915061.cos.ap-nanjing.myqcloud.com/images01/SSM%E6%95%B4%E5%90%88.assets/SSM-cover.webp" onerror="onerror=null;src='/img/404.jpg'" alt="cover of previous post"><div class="pagination-info"><div class="label">上一篇</div><div class="prev_info">SSM整合</div></div></a></div><div class="next-post pull-right"><a href="/posts/d438b6f1fced/"><img class="next-cover" src="https://zylai-cloud-pic-1306915061.cos.ap-nanjing.myqcloud.com/images01/Spring.assets/image-20220724093300702.png" onerror="onerror=null;src='/img/404.jpg'" alt="cover of next post"><div class="pagination-info"><div class="label">下一篇</div><div class="next_info">Spring框架</div></div></a></div></nav><div class="relatedPosts"><div class="headline"><i class="fas fa-thumbs-up fa-fw"></i><span>相关推荐</span></div><div class="relatedPosts-list"><div><a href="/posts/91d12734b70c/" title="SSM整合"><img class="cover" src="https://zylai-cloud-pic-1306915061.cos.ap-nanjing.myqcloud.com/images01/SSM%E6%95%B4%E5%90%88.assets/SSM-cover.webp" alt="cover"><div class="content is-center"><div class="date"><i class="far fa-calendar-alt fa-fw"></i> 2022-08-04</div><div class="title">SSM整合</div></div></a></div><div><a href="/posts/d438b6f1fced/" title="Spring框架"><img class="cover" src="https://zylai-cloud-pic-1306915061.cos.ap-nanjing.myqcloud.com/images01/Spring.assets/image-20220724093300702.png" alt="cover"><div class="content is-center"><div class="date"><i class="far fa-calendar-alt fa-fw"></i> 2022-08-02</div><div class="title">Spring框架</div></div></a></div><div><a href="/posts/9cf7da51c067/" title="MyBatis框架"><img class="cover" src="https://zylai-cloud-pic-1306915061.cos.ap-nanjing.myqcloud.com/images01/mybatis.assets/mybatis-logo.png" alt="cover"><div class="content is-center"><div class="date"><i class="far fa-calendar-alt fa-fw"></i> 2022-07-23</div><div class="title">MyBatis框架</div></div></a></div><div><a href="/posts/32afa3256671/" title="SpringBoot2自动装配原理以及入门使用"><img class="cover" src="https://zylai-cloud-pic-1306915061.cos.ap-nanjing.myqcloud.com/images01/SpringBoot-01.assets/springboot01.png" alt="cover"><div class="content is-center"><div class="date"><i class="far fa-calendar-alt fa-fw"></i> 2022-08-14</div><div class="title">SpringBoot2自动装配原理以及入门使用</div></div></a></div></div></div></div><div class="aside-content" id="aside-content"><div class="card-widget card-info"><div class="is-center"><div class="avatar-img"><img src="/img/avatar.jpg" onerror="this.onerror=null;this.src='/img/friend_404.gif'" alt="avatar"/></div><div class="author-info__name">zylai</div><div class="author-info__description">zylai && 管大虾の克星</div></div><div class="card-info-data site-data is-center"><a href="/archives/"><div class="headline">文章</div><div class="length-num">18</div></a><a href="/tags/"><div class="headline">标签</div><div class="length-num">14</div></a><a href="/categories/"><div class="headline">分类</div><div class="length-num">11</div></a></div><a id="card-info-btn" target="_blank" rel="noopener" href="https://github.com/zhaoyunlai"><i class="fab fa-github"></i><span>Follow Me</span></a><div class="card-info-social-icons is-center"><a class="social-icon" href="https://github.com/zhaoyunlai" target="_blank" title="Github"><i class="fab fa-github"></i></a><a class="social-icon" href="mailto:zylai0712@163.com" target="_blank" title="Email"><i class="fas fa-envelope"></i></a></div></div><div class="card-widget card-announcement"><div class="item-headline"><i class="fas fa-bullhorn fa-shake"></i><span>公告</span></div><div class="announcement_content">This is my blog</div></div><div class="sticky_layout"><div class="card-widget" id="card-toc"><div class="item-headline"><i class="fas fa-stream"></i><span>目录</span><span class="toc-percentage"></span></div><div class="toc-content"><ol class="toc"><li class="toc-item toc-level-1"><a class="toc-link"><span class="toc-text">SpringMVC</span></a><ol class="toc-child"><li class="toc-item toc-level-2"><a class="toc-link" href="#1-SpringMVC%E7%AE%80%E4%BB%8B"><span class="toc-text">1 SpringMVC简介</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#1-1-MVC"><span class="toc-text">1.1 MVC</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#1-2-SpringMVC"><span class="toc-text">1.2 SpringMVC</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#1-3-SpringMVC%E7%9A%84%E7%89%B9%E7%82%B9"><span class="toc-text">1.3 SpringMVC的特点</span></a></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#2-%E5%85%A5%E9%97%A8%E6%A1%88%E4%BE%8B%F0%9F%92%83"><span class="toc-text">2 入门案例💃</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#2-1-%E5%88%9B%E5%BB%BAMaven%E5%B7%A5%E7%A8%8B"><span class="toc-text">2.1 创建Maven工程</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#2-2-%E5%9C%A8web-xml%E4%B8%AD%E9%85%8D%E7%BD%AEDispatcherServlet"><span class="toc-text">2.2 在web.xml中配置DispatcherServlet</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#2-2-1-%E9%85%8D%E7%BD%AE%E5%8C%B9%E9%85%8D%E8%AF%B7%E6%B1%82%E8%B7%AF%E5%BE%84"><span class="toc-text">2.2.1 配置匹配请求路径</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#2-2-2-%E9%85%8D%E7%BD%AE%E5%88%9D%E5%A7%8B%E5%8C%96%E6%97%B6%E6%9C%BA"><span class="toc-text">2.2.2 配置初始化时机</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#2-2-3-%E9%85%8D%E7%BD%AE%E6%96%87%E4%BB%B6%E7%9A%84%E8%B7%AF%E5%BE%84"><span class="toc-text">2.2.3 配置文件的路径</span></a></li></ol></li><li class="toc-item toc-level-3"><a class="toc-link" href="#2-3-%E5%88%9B%E5%BB%BA%E8%AF%B7%E6%B1%82%E6%8E%A7%E5%88%B6%E5%99%A8"><span class="toc-text">2.3 创建请求控制器</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#%E6%8E%A7%E5%88%B6%E5%99%A8%E6%96%B9%E6%B3%95%E5%8C%B9%E9%85%8D%E8%AF%B7%E6%B1%82"><span class="toc-text">控制器方法匹配请求</span></a></li></ol></li><li class="toc-item toc-level-3"><a class="toc-link" href="#2-4-%E5%88%9B%E5%BB%BASpringMVC%E7%9A%84%E9%85%8D%E7%BD%AE%E6%96%87%E4%BB%B6"><span class="toc-text">2.4 创建SpringMVC的配置文件</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#2-5-%E8%AF%B7%E6%B1%82%E8%AE%BF%E9%97%AE%E9%A1%B5%E9%9D%A2%E5%92%8C%E8%B7%B3%E8%BD%AC%E9%A1%B5%E9%9D%A2"><span class="toc-text">2.5 请求访问页面和跳转页面</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#2-5-1-%E5%88%9B%E5%BB%BA%E7%9A%84%E4%BD%8D%E7%BD%AE"><span class="toc-text">2.5.1 创建的位置</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#2-5-2-%E8%AE%BF%E9%97%AE%E9%A1%B5%E9%9D%A2"><span class="toc-text">2.5.2 访问页面</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#2-5-3-%E9%A1%B5%E9%9D%A2%E4%B8%AD%E7%9A%84%E8%B7%AF%E5%BE%84%E8%A7%A3%E6%9E%90"><span class="toc-text">2.5.3 页面中的路径解析</span></a></li></ol></li><li class="toc-item toc-level-3"><a class="toc-link" href="#%E6%80%BB%E7%BB%93"><span class="toc-text">总结</span></a></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#3-RequestMapping%E6%B3%A8%E8%A7%A3%F0%9F%9A%80"><span class="toc-text">3 RequestMapping注解🚀</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#3-1-%E6%A0%87%E8%AF%86%E7%9A%84%E4%BD%8D%E7%BD%AE"><span class="toc-text">3.1 标识的位置</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#3-2-value%E5%B1%9E%E6%80%A7%E2%AD%90"><span class="toc-text">3.2 value属性⭐</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#3-3-method%E5%B1%9E%E6%80%A7%E2%AD%90"><span class="toc-text">3.3 method属性⭐</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#3-4-params%E5%B1%9E%E6%80%A7%EF%BC%88%E4%BA%86%E8%A7%A3%EF%BC%89"><span class="toc-text">3.4 params属性（了解）</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#3-5-headers%E5%B1%9E%E6%80%A7%EF%BC%88%E4%BA%86%E8%A7%A3%EF%BC%89"><span class="toc-text">3.5 headers属性（了解）</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#3-6-SpringMVC%E6%94%AF%E6%8C%81ant%E9%A3%8E%E6%A0%BC%E7%9A%84%E8%B7%AF%E5%BE%84"><span class="toc-text">3.6 SpringMVC支持ant风格的路径</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#3-7-%E4%BD%BF%E7%94%A8%E8%B7%AF%E5%BE%84%E4%B8%AD%E7%9A%84%E5%8D%A0%E4%BD%8D%E7%AC%A6%EF%BC%88%E9%87%8D%E7%82%B9%EF%BC%89%F0%9F%8C%9F"><span class="toc-text">3.7 使用路径中的占位符（重点）🌟</span></a></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#4-SpringMVC%E8%8E%B7%E5%8F%96%E8%AF%B7%E6%B1%82%E5%8F%82%E6%95%B0%F0%9F%93%9F"><span class="toc-text">4 SpringMVC获取请求参数📟</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#4-1-%E9%80%9A%E8%BF%87servletAPI%E8%8E%B7%E5%8F%96"><span class="toc-text">4.1 通过servletAPI获取</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#4-2-%E9%80%9A%E8%BF%87%E6%8E%A7%E5%88%B6%E5%99%A8%E6%96%B9%E6%B3%95%E7%9A%84%E5%BD%A2%E5%8F%82%E8%8E%B7%E5%8F%96"><span class="toc-text">4.2 通过控制器方法的形参获取</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#4-3-RequestParam%E6%B3%A8%E8%A7%A3%F0%9F%8C%8A"><span class="toc-text">4.3 @RequestParam注解🌊</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#4-4-RequestHeader%E6%B3%A8%E8%A7%A3"><span class="toc-text">4.4 @RequestHeader注解</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#4-5-CookieValue%E6%B3%A8%E8%A7%A3"><span class="toc-text">4.5 @CookieValue注解</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#4-6-%E9%80%9A%E8%BF%87%E6%8E%A7%E5%88%B6%E5%99%A8%E6%96%B9%E6%B3%95%E7%9A%84%E5%AE%9E%E4%BD%93%E7%B1%BB%E7%B1%BB%E5%9E%8B%E7%9A%84%E5%BD%A2%E5%8F%82%E8%8E%B7%E5%8F%96%E2%9C%8C%EF%B8%8F"><span class="toc-text">4.6 通过控制器方法的实体类类型的形参获取✌️</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#4-7-%E8%AE%BE%E7%BD%AE%E7%BC%96%E7%A0%81-%F0%9F%8F%AE"><span class="toc-text">4.7 设置编码 🏮</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#%E5%9C%A8web-xml%E4%B8%AD%E8%AE%BE%E7%BD%AE"><span class="toc-text">在web.xml中设置</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#%E6%BA%90%E7%A0%81%E8%A7%A3%E6%9E%90"><span class="toc-text">源码解析</span></a></li></ol></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#5-%E5%9F%9F%E5%AF%B9%E8%B1%A1%E5%85%B1%E4%BA%AB%E6%95%B0%E6%8D%AE%F0%9F%A5%98"><span class="toc-text">5 域对象共享数据🥘</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#5-1-%E9%80%9A%E8%BF%87ModelAndView%E5%90%91%E8%AF%B7%E6%B1%82%E5%9F%9F%E5%85%B1%E4%BA%AB%E6%95%B0%E6%8D%AE"><span class="toc-text">5.1 通过ModelAndView向请求域共享数据</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#5-2-%E9%80%9A%E8%BF%87Model%E5%90%91%E8%AF%B7%E6%B1%82%E5%9F%9F%E5%85%B1%E4%BA%AB%E6%95%B0%E6%8D%AE"><span class="toc-text">5.2 通过Model向请求域共享数据</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#5-3-%E9%80%9A%E8%BF%87ModelMap%E5%90%91%E8%AF%B7%E6%B1%82%E5%9F%9F%E5%85%B1%E4%BA%AB%E6%95%B0%E6%8D%AE"><span class="toc-text">5.3 通过ModelMap向请求域共享数据</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#5-4-%E9%80%9A%E8%BF%87Map%E5%90%91%E8%AF%B7%E6%B1%82%E5%9F%9F%E5%85%B1%E4%BA%AB%E6%95%B0%E6%8D%AE"><span class="toc-text">5.4 通过Map向请求域共享数据</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#5-5-Model%E5%92%8CModelMap%E5%92%8CMap%E7%9A%84%E5%85%B3%E7%B3%BB"><span class="toc-text">5.5 Model和ModelMap和Map的关系</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#5-6-%E5%85%B1%E4%BA%ABsession%E5%9F%9F%E5%92%8Capplication%E5%9F%9F%E4%B8%AD%E7%9A%84%E6%95%B0%E6%8D%AE"><span class="toc-text">5.6 共享session域和application域中的数据</span></a></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#6-SpringMVC%E8%A7%86%E5%9B%BE%F0%9F%8C%85"><span class="toc-text">6 SpringMVC视图🌅</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#6-1-Thymeleaf%E8%A7%86%E5%9B%BE"><span class="toc-text">6.1 Thymeleaf视图</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#6-2-%E8%BD%AC%E5%8F%91%E8%A7%86%E5%9B%BE"><span class="toc-text">6.2 转发视图</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#6-3-%E9%87%8D%E5%AE%9A%E5%90%91%E8%A7%86%E5%9B%BE"><span class="toc-text">6.3 重定向视图</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#6-4-%E8%A7%86%E5%9B%BE%E6%8E%A7%E5%88%B6%E5%99%A8"><span class="toc-text">6.4 视图控制器</span></a></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#7-RESTful%F0%9F%98%AA"><span class="toc-text">7 RESTful😪</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#7-1-RESTful%E7%AE%80%E4%BB%8B"><span class="toc-text">7.1 RESTful简介</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#7-2-RESTful%E7%9A%84%E5%AE%9E%E7%8E%B0"><span class="toc-text">7.2 RESTful的实现</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#7-3-%E5%A4%84%E7%90%86PUT%E5%92%8CDELETE%E8%AF%B7%E6%B1%82"><span class="toc-text">7.3 处理PUT和DELETE请求</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#%E6%BA%90%E7%A0%81%E5%88%86%E6%9E%90"><span class="toc-text">源码分析</span></a></li></ol></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#8-RESTful%E6%A1%88%E4%BE%8B%F0%9F%98%91"><span class="toc-text">8 RESTful案例😑</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#8-1-%E5%8A%9F%E8%83%BD"><span class="toc-text">8.1 功能</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#8-2-%E5%A4%84%E7%90%86%E9%9D%99%E6%80%81%E8%B5%84%E6%BA%90"><span class="toc-text">8.2 处理静态资源</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#%E7%94%B1css%E6%96%87%E4%BB%B6%E5%BC%95%E5%85%A5"><span class="toc-text">由css文件引入</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#DispatcherServlet%E5%92%8CTomcat%E7%9A%84DefaultServlet"><span class="toc-text">DispatcherServlet和Tomcat的DefaultServlet</span></a></li></ol></li><li class="toc-item toc-level-3"><a class="toc-link" href="#8-3-%E5%8A%9F%E8%83%BD%E5%AE%9E%E7%8E%B0"><span class="toc-text">8.3 功能实现</span></a></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#9-SpringMVC%E5%A4%84%E7%90%86ajax%E8%AF%B7%E6%B1%82%F0%9F%8C%9F"><span class="toc-text">9 SpringMVC处理ajax请求🌟</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#9-1-ajax%E4%BB%8B%E7%BB%8D%F0%9F%A4%A3"><span class="toc-text">9.1 ajax介绍🤣</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#%E6%9C%8D%E5%8A%A1%E7%AB%AF%E6%B8%B2%E6%9F%93%E4%B8%8Eajax%E6%B8%B2%E6%9F%93"><span class="toc-text">服务端渲染与ajax渲染</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#%E5%89%8D%E5%90%8E%E7%AB%AF%E5%88%86%E7%A6%BB"><span class="toc-text">前后端分离</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#%E5%BC%82%E6%AD%A5%E5%92%8C%E5%90%8C%E6%AD%A5"><span class="toc-text">异步和同步</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#axios"><span class="toc-text">axios</span></a></li></ol></li><li class="toc-item toc-level-3"><a class="toc-link" href="#9-2-RequestBody%E6%B3%A8%E8%A7%A3"><span class="toc-text">9.2 @RequestBody注解</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#9-3-RequestBody%E6%B3%A8%E8%A7%A3%E5%B0%86json%E6%A0%BC%E5%BC%8F%E7%9A%84%E6%95%B0%E6%8D%AE%E8%BD%AC%E4%B8%BAjava%E5%AF%B9%E8%B1%A1%F0%9F%8D%B0"><span class="toc-text">9.3 @RequestBody注解将json格式的数据转为java对象🍰</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#1%E3%80%81%E5%AF%BC%E5%85%A5jackson%E7%9A%84%E4%BE%9D%E8%B5%96"><span class="toc-text">1、导入jackson的依赖</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#2%E3%80%81%E5%9C%A8SpringMVC%E9%85%8D%E7%BD%AE%E6%96%87%E4%BB%B6%E4%B8%AD%E8%AE%BE%E7%BD%AE%E5%BC%80%E5%90%AFmvc%E7%9A%84%E6%B3%A8%E8%A7%A3%E9%A9%B1%E5%8A%A8"><span class="toc-text">2、在SpringMVC配置文件中设置开启mvc的注解驱动</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#3%E3%80%81%E5%9C%A8%E6%8E%A7%E5%88%B6%E5%99%A8%E6%96%B9%E6%B3%95%E7%9A%84%E5%BD%A2%E5%8F%82%E5%89%8D%E8%AE%BE%E7%BD%AE-RequestBody%E6%B3%A8%E8%A7%A3"><span class="toc-text">3、在控制器方法的形参前设置@RequestBody注解</span></a></li></ol></li><li class="toc-item toc-level-3"><a class="toc-link" href="#9-4-ResponseBody%E6%B3%A8%E8%A7%A3"><span class="toc-text">9.4 @ResponseBody注解</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#9-5-ResponseBody%E6%B3%A8%E8%A7%A3%E5%93%8D%E5%BA%94%E7%BB%99%E6%B5%8F%E8%A7%88%E5%99%A8json%E6%A0%BC%E5%BC%8F%E6%95%B0%E6%8D%AE"><span class="toc-text">9.5 @ResponseBody注解响应给浏览器json格式数据</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#java-json"><span class="toc-text">java --&gt; json</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#%E6%AD%A5%E9%AA%A4%EF%BC%9A%EF%BC%88%E5%92%8C%E4%B8%8A%E9%9D%A2%E7%9A%84%E5%B7%AE%E4%B8%8D%E5%A4%9A%EF%BC%89"><span class="toc-text">步骤：（和上面的差不多）</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#%E8%BD%AC%E6%8D%A2%E5%85%B3%E7%B3%BB"><span class="toc-text">转换关系</span></a></li></ol></li><li class="toc-item toc-level-3"><a class="toc-link" href="#9-6-RestController%E6%B3%A8%E8%A7%A3"><span class="toc-text">9.6 @RestController注解</span></a></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#10-%E6%96%87%E4%BB%B6%E4%B8%8A%E4%BC%A0%E5%92%8C%E4%B8%8B%E8%BD%BD"><span class="toc-text">10 文件上传和下载</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#10-1-%E6%96%87%E4%BB%B6%E4%B8%8B%E8%BD%BD"><span class="toc-text">10.1 文件下载</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#10-2-%E6%96%87%E4%BB%B6%E4%B8%8A%E4%BC%A0"><span class="toc-text">10.2 文件上传</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#10-3-%E6%96%87%E4%BB%B6%E4%B8%8A%E4%BC%A0%E7%9A%84%E9%87%8D%E5%91%BD%E5%90%8D%E9%97%AE%E9%A2%98"><span class="toc-text">10.3 文件上传的重命名问题</span></a></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#11-%E6%8B%A6%E6%88%AA%E5%99%A8"><span class="toc-text">11 拦截器</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#11-1-%E6%8B%A6%E6%88%AA%E5%99%A8%E7%9A%84%E9%85%8D%E7%BD%AE"><span class="toc-text">11.1 拦截器的配置</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#11-2-%E6%8B%A6%E6%88%AA%E5%99%A8%E7%9A%84%E4%B8%89%E4%B8%AA%E6%8A%BD%E8%B1%A1%E6%96%B9%E6%B3%95"><span class="toc-text">11.2 拦截器的三个抽象方法</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#11-3-%E5%A4%9A%E4%B8%AA%E6%8B%A6%E6%88%AA%E5%99%A8%E7%9A%84%E6%89%A7%E8%A1%8C%E9%A1%BA%E5%BA%8F"><span class="toc-text">11.3 多个拦截器的执行顺序</span></a></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#12-%E5%BC%82%E5%B8%B8%E5%A4%84%E7%90%86%E5%99%A8"><span class="toc-text">12 异常处理器</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#1%E3%80%81%E5%9F%BA%E4%BA%8E%E9%85%8D%E7%BD%AE%E7%9A%84%E5%BC%82%E5%B8%B8%E5%A4%84%E7%90%86"><span class="toc-text">1、基于配置的异常处理</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#2%E3%80%81%E5%9F%BA%E4%BA%8E%E6%B3%A8%E8%A7%A3%E7%9A%84%E5%BC%82%E5%B8%B8%E5%A4%84%E7%90%86"><span class="toc-text">2、基于注解的异常处理</span></a></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#13-%E6%B3%A8%E8%A7%A3%E9%85%8D%E7%BD%AESpringMVC"><span class="toc-text">13 注解配置SpringMVC</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#1%E3%80%81%E5%88%9B%E5%BB%BA%E5%88%9D%E5%A7%8B%E5%8C%96%E7%B1%BB%EF%BC%8C%E4%BB%A3%E6%9B%BFweb-xml"><span class="toc-text">1、创建初始化类，代替web.xml</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#2%E3%80%81%E5%88%9B%E5%BB%BASpringConfig%E9%85%8D%E7%BD%AE%E7%B1%BB%EF%BC%8C%E4%BB%A3%E6%9B%BFspring%E7%9A%84%E9%85%8D%E7%BD%AE%E6%96%87%E4%BB%B6"><span class="toc-text">2、创建SpringConfig配置类，代替spring的配置文件</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#3%E3%80%81%E5%88%9B%E5%BB%BAWebConfig%E9%85%8D%E7%BD%AE%E7%B1%BB%EF%BC%8C%E4%BB%A3%E6%9B%BFSpringMVC%E7%9A%84%E9%85%8D%E7%BD%AE%E6%96%87%E4%BB%B6"><span class="toc-text">3、创建WebConfig配置类，代替SpringMVC的配置文件</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#4%E3%80%81%E6%B5%8B%E8%AF%95%E5%8A%9F%E8%83%BD"><span class="toc-text">4、测试功能</span></a></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#14-SpringMVC%E6%89%A7%E8%A1%8C%E6%B5%81%E7%A8%8B"><span class="toc-text">14 SpringMVC执行流程</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#1%E3%80%81SpringMVC%E5%B8%B8%E7%94%A8%E7%BB%84%E4%BB%B6"><span class="toc-text">1、SpringMVC常用组件</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#2%E3%80%81DispatcherServlet%E5%88%9D%E5%A7%8B%E5%8C%96%E8%BF%87%E7%A8%8B"><span class="toc-text">2、DispatcherServlet初始化过程</span></a><ol class="toc-child"><li class="toc-item toc-level-5"><a class="toc-link" href="#a-%E5%88%9D%E5%A7%8B%E5%8C%96WebApplicationContext"><span class="toc-text">a&gt;初始化WebApplicationContext</span></a></li><li class="toc-item toc-level-5"><a class="toc-link" href="#b-%E5%88%9B%E5%BB%BAWebApplicationContext"><span class="toc-text">b&gt;创建WebApplicationContext</span></a></li><li class="toc-item toc-level-5"><a class="toc-link" href="#c-DispatcherServlet%E5%88%9D%E5%A7%8B%E5%8C%96%E7%AD%96%E7%95%A5"><span class="toc-text">c&gt;DispatcherServlet初始化策略</span></a></li></ol></li></ol></li><li class="toc-item toc-level-3"><a class="toc-link" href="#3%E3%80%81DispatcherServlet%E8%B0%83%E7%94%A8%E7%BB%84%E4%BB%B6%E5%A4%84%E7%90%86%E8%AF%B7%E6%B1%82"><span class="toc-text">3、DispatcherServlet调用组件处理请求</span></a><ol class="toc-child"><li class="toc-item toc-level-5"><a class="toc-link" href="#a-processRequest"><span class="toc-text">a&gt;processRequest()</span></a></li><li class="toc-item toc-level-5"><a class="toc-link" href="#b-doService"><span class="toc-text">b&gt;doService()</span></a></li><li class="toc-item toc-level-5"><a class="toc-link" href="#c-doDispatch"><span class="toc-text">c&gt;doDispatch()</span></a></li><li class="toc-item toc-level-5"><a class="toc-link" href="#d-processDispatchResult"><span class="toc-text">d&gt;processDispatchResult()</span></a></li></ol></li></ol></li><li class="toc-item toc-level-3"><a class="toc-link" href="#4%E3%80%81SpringMVC%E7%9A%84%E6%89%A7%E8%A1%8C%E6%B5%81%E7%A8%8B"><span class="toc-text">4、SpringMVC的执行流程</span></a></li></ol></li></ol></li></ol></div></div><div class="card-widget card-recent-post"><div class="item-headline"><i class="fas fa-history"></i><span>最新文章</span></div><div class="aside-list"><div class="aside-list-item"><a class="thumbnail" href="/posts/22ef9dff46af/" title="移动互联网开发技术-第三次实验"><img src="https://zylai-cloud-pic-1306915061.cos.ap-nanjing.myqcloud.com/images01/%E7%B3%BB%E7%BB%9F%E8%AE%BE%E8%AE%A1.assets/sdnu-background2.jpg" onerror="this.onerror=null;this.src='/img/404.jpg'" alt="移动互联网开发技术-第三次实验"/></a><div class="content"><a class="title" href="/posts/22ef9dff46af/" title="移动互联网开发技术-第三次实验">移动互联网开发技术-第三次实验</a><time datetime="2022-10-15T01:43:30.000Z" title="发表于 2022-10-15 09:43:30">2022-10-15</time></div></div><div class="aside-list-item"><a class="thumbnail" href="/posts/85838fb07a8b/" title="学生成长动态追踪系统-学生使用手册"><img src="https://zylai-cloud-pic-1306915061.cos.ap-nanjing.myqcloud.com/images01/%E7%B3%BB%E7%BB%9F%E8%AE%BE%E8%AE%A1.assets/sdnu-background2.jpg" onerror="this.onerror=null;this.src='/img/404.jpg'" alt="学生成长动态追踪系统-学生使用手册"/></a><div class="content"><a class="title" href="/posts/85838fb07a8b/" title="学生成长动态追踪系统-学生使用手册">学生成长动态追踪系统-学生使用手册</a><time datetime="2022-09-25T11:43:30.000Z" title="发表于 2022-09-25 19:43:30">2022-09-25</time></div></div><div class="aside-list-item"><a class="thumbnail" href="/posts/896511b44bb7/" title="学生成长动态追踪系统-家长使用手册"><img src="https://zylai-cloud-pic-1306915061.cos.ap-nanjing.myqcloud.com/images01/%E7%B3%BB%E7%BB%9F%E8%AE%BE%E8%AE%A1.assets/sdnu-background2.jpg" onerror="this.onerror=null;this.src='/img/404.jpg'" alt="学生成长动态追踪系统-家长使用手册"/></a><div class="content"><a class="title" href="/posts/896511b44bb7/" title="学生成长动态追踪系统-家长使用手册">学生成长动态追踪系统-家长使用手册</a><time datetime="2022-09-25T11:43:29.000Z" title="发表于 2022-09-25 19:43:29">2022-09-25</time></div></div><div class="aside-list-item"><a class="thumbnail" href="/posts/78afc3f0ab42/" title="Shiro权限安全框架的使用"><img src="https://zylai-cloud-pic-1306915061.cos.ap-nanjing.myqcloud.com/images01/shiro.assets/image-20220929162947122.png" onerror="this.onerror=null;this.src='/img/404.jpg'" alt="Shiro权限安全框架的使用"/></a><div class="content"><a class="title" href="/posts/78afc3f0ab42/" title="Shiro权限安全框架的使用">Shiro权限安全框架的使用</a><time datetime="2022-09-18T11:43:29.000Z" title="发表于 2022-09-18 19:43:29">2022-09-18</time></div></div><div class="aside-list-item"><a class="thumbnail" href="/posts/e32230f09e09/" title="学生成长动态追踪系统"><img src="https://zylai-cloud-pic-1306915061.cos.ap-nanjing.myqcloud.com/images01/%E7%B3%BB%E7%BB%9F%E8%AE%BE%E8%AE%A1.assets/sdnu-background2.jpg" onerror="this.onerror=null;this.src='/img/404.jpg'" alt="学生成长动态追踪系统"/></a><div class="content"><a class="title" href="/posts/e32230f09e09/" title="学生成长动态追踪系统">学生成长动态追踪系统</a><time datetime="2022-08-25T11:43:29.000Z" title="发表于 2022-08-25 19:43:29">2022-08-25</time></div></div></div></div></div></div></main><footer id="footer" style="background-image: url('https://zylai-cloud-pic-1306915061.cos.ap-nanjing.myqcloud.com/images01/SpringMVC.assets/SpringMVC-logo.png')"><div id="footer-wrap"><div class="copyright">&copy;2020 - 2022 By zylai</div><div class="framework-info"><span>框架 </span><a target="_blank" rel="noopener" href="https://hexo.io">Hexo</a><span class="footer-separator">|</span><span>主题 </span><a target="_blank" rel="noopener" href="https://github.com/jerryc127/hexo-theme-butterfly">Butterfly</a></div></div></footer></div><div id="rightside"><div id="rightside-config-hide"><button id="readmode" type="button" title="阅读模式"><i class="fas fa-book-open"></i></button><button id="darkmode" type="button" title="浅色和深色模式转换"><i class="fas fa-adjust"></i></button><button id="hide-aside-btn" type="button" title="单栏和双栏切换"><i class="fas fa-arrows-alt-h"></i></button></div><div id="rightside-config-show"><button id="rightside_config" type="button" title="设置"><i class="fas fa-cog fa-spin"></i></button><button class="close" id="mobile-toc-button" type="button" title="目录"><i class="fas fa-list-ul"></i></button><button id="go-up" type="button" title="回到顶部"><i class="fas fa-arrow-up"></i></button></div></div><div id="local-search"><div class="search-dialog"><nav class="search-nav"><span class="search-dialog-title">搜索</span><span id="loading-status"></span><button class="search-close-button"><i class="fas fa-times"></i></button></nav><div class="is-center" id="loading-database"><i class="fas fa-spinner fa-pulse"></i><span>  数据库加载中</span></div><div class="search-wrap"><div id="local-search-input"><div class="local-search-box"><input class="local-search-box--input" placeholder="搜索文章" type="text"/></div></div><hr/><div id="local-search-results"></div></div></div><div id="search-mask"></div></div><div><script src="/js/utils.js"></script><script src="/js/main.js"></script><script src="https://cdn.jsdelivr.net/npm/@fancyapps/ui/dist/fancybox.umd.min.js"></script><script src="/js/search/local-search.js"></script><div class="js-pjax"></div><script defer="defer" id="ribbon" src="https://cdn.jsdelivr.net/npm/butterfly-extsrc/dist/canvas-ribbon.min.js" size="150" alpha="0.6" zIndex="-1" mobile="false" data-click="true"></script><script async data-pjax src="//busuanzi.ibruce.info/busuanzi/2.3/busuanzi.pure.mini.js"></script></div><!-- hexo injector body_end start --><script data-pjax>function electric_clock_injector_config(){
                var parent_div_git = document.getElementsByClassName('sticky_layout')[0];
                var item_html = '<div class="card-widget card-clock"><div class="card-glass"><div class="card-background"><div class="card-content"><div id="hexo_electric_clock"><img id="card-clock-loading" src="https://cdn.jsdelivr.net/gh/Zfour/Butterfly-clock/clock/images/weather/loading.gif" style="height: 120px; width: 100%;" data-ll-status="loading" class="entered loading"></div></div></div></div></div>';
                console.log('已挂载electric_clock')
                // parent_div_git.innerHTML=item_html+parent_div_git.innerHTML // 无报错，但不影响使用(支持pjax跳转)
                parent_div_git.insertAdjacentHTML("afterbegin",item_html) // 有报错，但不影响使用(支持pjax跳转)
            }if( document.getElementsByClassName('sticky_layout')[0] && (location.pathname ==='/'|| '/' ==='all')){

            electric_clock_injector_config()
        } </script><script src="https://pv.sohu.com/cityjson?ie=utf-8"></script><script data-pjax  src="https://cdn.jsdelivr.net/gh/Zfour/hexo-electric-clock@1.0.6/clock.js"></script><!-- hexo injector body_end end --></body></html>